├── .gitignore ├── LICENSE.md ├── README.md ├── config ├── Vagrant │ └── Vagrantfile └── grunt │ ├── Gruntfile.js │ └── package.json └── www └── index.php /.gitignore: -------------------------------------------------------------------------------- 1 | # always-ignore extensions 2 | *.diff 3 | *.err 4 | *.orig 5 | *.log 6 | *.rej 7 | *.swo 8 | *.swp 9 | *.vi 10 | *~ 11 | *.sass-cache 12 | 13 | # OS or Editor folders 14 | .DS_Store 15 | Thumbs.db 16 | .cache 17 | .project 18 | .settings 19 | .tmproj 20 | *.esproj 21 | nbproject 22 | 23 | # Dreamweaver added files 24 | _notes 25 | dwsync.xml 26 | 27 | # WPMU Project specific stuff 28 | wp-config.php 29 | wp-content/uploads 30 | .htaccess 31 | sitemap.xml.gz 32 | sitemap.xml 33 | feed.xml 34 | .htaccess 35 | wp-content/cache 36 | wp-content/w3tc-config 37 | wp-content/uploads 38 | wp-content/db.php 39 | wp-content/object-cache.php 40 | wp-content/advanced-cache.php 41 | config/Vagrant/.vagrant/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2014 HootSuite Media Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### *Project Status Update* 2 | 3 | *This project was started early in 2013 and the associated internal project was never completed and shipped. Consequently it is not under active development or being updated. Pull requests for updates will be reviewed and accepted where appropriate.* 4 | 5 | # Vagrant and Wordpress Multi Site 6 | 7 | ## Overview 8 | 9 | HootSuite needed a Vagrant box that was configured to host Wordpress Multisite complete with custom domain mapping. At the outset of the project our requirements were: 10 | 11 | * Vagrant box tuned for Wordpress Multi Site Development 12 | * Build tools contained on the Vagrant Box that easily work with multiple themes 13 | * Ability to map domains with high degree of flexibility 14 | 15 | This project solves a niche issue for us in a very particular way and there are many things required to make this 100% stable and usable for any project required to do after this starting point. 16 | 17 | ## Preparation 18 | 19 | * Install [Vagrant](http://www.vagrantup.com/) (last tested with 1.5) 20 | * [Installation Instructions](http://docs.vagrantup.com/v2/installation/index.html) 21 | 22 | ### How to access the Database on the Vagrant Box 23 | During the following steps accessing the database is required. The Vagrant box includes MySQL but not phpMyAdmin. Use [Sequel Pro](http://www.sequelpro.com/) to connect to the database using these settings: 24 | 25 | * MySql Host: `127.0.0.1` 26 | * Username: `root` 27 | * Password: `leave this blank` 28 | * Database: `wordpress` 29 | * Port: `don't edit this` 30 | * SSH Host: `127.0.0.1` 31 | * SSH User: `vagrant` 32 | * SSH Password: `vagrant` 33 | * SSH Port: `2222` 34 | 35 | This Vagrant box by default includes a database called `Wordpress`. These instructions will always use and reference the `Wordpress` DB however others can be added and used as required. 36 | 37 | ### Editing Local Hosts File 38 | 39 | Vagrant needs an IP in order to initialize a server but we want to map subdomains to mirror our production environment. For this example, use `wordpress.mydomain.com` as the parent installation path and create `site1.mydomain.com`, `site2.mydomain.com` etc. For development `.local` top level domains will be used. 40 | 41 | Prior to installing Wordpress edit your local `/etc/hosts`/ file to include these lines: 42 | 43 | ``` 44 | 192.168.37.21 wordpress.mydomain.local 45 | 192.168.37.21 site1.mydomain.local 46 | 192.168.37.21 site1.wordpress.mydomain.local 47 | ``` 48 | 49 | * The IP listed is taken from the Vagrantfile 50 | * Lines 2 and 3 are required for Wordpress to set up and then domain map domains when they are added 51 | * Lines 2 and 3 can be repeated to add more sites (site2, site3 etc) 52 | * `mydomain.local` can be replaced with project specific URL's 53 | 54 | ### Shared Folders 55 | 56 | This Vagrant Box has two folders that are shared between your local machine. 57 | 58 | | Local Path | Vagrant Path | 59 | | ------------- | ------------- | 60 | | / | /vagrant/ | 61 | | /www/ | /ebs1/www/ | 62 | 63 | 64 | ## Getting Started 65 | 66 | ### Initialization 67 | * Clone the repository: `git clone https://github.com/hootsuite/wordpress-multisite-vagrant.git projectName` 68 | * Navigate to the Vagrant folder `cd projectName/config/vagrant/` 69 | * Download the Vagrant Box and `vagrant up` to initialize the virtual machine 70 | * Load `http://wordpress.mydomain.local` to test if everything is working, if not visit [Vagrant Docs](http://docs.vagrantup.com/v2/) to troubleshoot. 71 | 72 | 73 | ### Install Wordpress MultiSite 74 | 75 | * Remove `index.php` in the Vagrant `/www/` folder (it's there to confirm installation went properly) 76 | * [Install Wordpress](http://codex.wordpress.org/Installing_WordPress) in the `www` folder 77 | * [Configure Wordpress for multisite](http://codex.wordpress.org/Create_A_Network) 78 | * when prompted select *sub domain* set up instead of *sub directories* 79 | * After creating the network there will be a red error at the top of the page (**Warning, Wildcard DNS may not be configured correctly!** ) Ignore this, as it is handled with local edits to `/etc/hosts`/ and domain mapping. 80 | * Install [Wordpress MU Domain Mapping](http://wordpress.org/extend/plugins/wordpress-mu-domain-mapping/) and [configure it](http://wordpress.org/extend/plugins/wordpress-mu-domain-mapping/installation/). **Note**: Follow steps 1-3. This plugin has unusual configuration options, read the configuration notes! 81 | 82 | ### Add a Domain 83 | 84 | * Ensure that the A records for the intended domain have been added to `/etc/hosts` 85 | * **Menu: My Sites > Network Admin > Plugins** - *Network Enable* Wordpress MultiSite Domain Mapping Plugin 86 | * **Menu: My Sites > Network Admin > Settings > Domain Mapping** - Leave inputs blank and deselect everything except for 2. Permanent redirect and click **Save** 87 | * **Menu: My Sites > Network Admin > Sites > Create New Site** Create your new site. Use the same site that you mapped in `/etc/hosts` (eg site1.wordpress.mydomain.local - we will remap this shortly) 88 | * Get the ID of this site: 89 | * **Menu: My Site > Network admin > Sites** 90 | * Get the Site ID either by hovering over the `Domain title` or installing the [Show Site ID Columns Plugin](http://halfelf.org/hacks/site-id-columns-multisite/) 91 | * The first site created should be `id=2` 92 | * **Menu: My Sites > Network Admin > Settings > Domains** - Under "New Domain" add: 93 | * Site ID = ID in the above step (eg 2) 94 | * Domain = New requested domain (`site1.mydomain.local`) 95 | * Primary: Leave this checked 96 | * Visit [http://site1.mydomain.local](http://site1.mydomain.local) in the browser 97 | * You're up and running! Enjoy a cold beverage! 98 | 99 | ## Grunt 100 | 101 | The Vagrant box includes [Grunt.js](http://gruntjs.com) preinstalled and is ready to use without installing it on your local machine. Alternatively you can install and configure Grunt on your own machine. 102 | 103 | ### Installing Grunt 104 | 105 | * SSH into the Vagrant Box `vagrant ssh` (while in `config/vagrant`) 106 | * Navigate to the directory containing all the configuration files (`cd /vagrant/config/grunt`) 107 | * Install all of the plugins by running `npm install`. 108 | 109 | This will install: 110 | 111 | * [Less](https://github.com/gruntjs/grunt-contrib-less) 112 | * [Sass](https://github.com/gruntjs/grunt-contrib-sass) 113 | * [Compass](https://github.com/gruntjs/grunt-contrib-compass) 114 | * [JSHint](https://github.com/gruntjs/grunt-contrib-JSHint) 115 | * [Uglify](https://github.com/gruntjs/grunt-contrib-uglify) 116 | * [Coffee Script](https://github.com/gruntjs/grunt-contrib-coffee) 117 | * [Concat](https://github.com/gruntjs/grunt-contrib-concat) 118 | * [Watch](https://github.com/gruntjs/grunt-contrib-watch) 119 | 120 | ### The Gruntfile 121 | You can [customize your Gruntfile](http://gruntjs.com/configuring-tasks) how you want. These are the included tasks. 122 | 123 | First, replace our theme name with yours: 124 | ``` 125 | theme: `/ebs1/www/wp-content/themes/hootsuite` 126 | ``` 127 | 128 | ### Less 129 | 130 | This Gruntfile presumes that you have a main css file (`css/less/styles.less`) that `@imports` all other ones for your project and compiles them to `css/styles.less`. If this isn't the case you'll need to edit the Gruntfile to reflect this. 131 | 132 | The following commands are available: 133 | 134 | * `grunt less:development` - builds the CSS but does not compress it 135 | * `grunt less:production` - builds and compresses the CSS with yuicompress 136 | * `grunt watch:less` - Watches all less files and runs `grunt less:development` when any file is saved 137 | 138 | Any files that are not built from `css/less/styles.less` will have to have additional tasks written for them. (eg `css/less/ie.less`) 139 | 140 | ### Javascript 141 | This Gruntfile works for multiple themes. For many projects, paths can be written directly into the Uglify tasks however for this project the Gruntfile looks for and parses a theme specific file (`js/dev/config.json`) and imports that into any tasks that require it. The syntax for the `js/dev/config.json` file is: 142 | 143 | ``` 144 | { 145 | "files": [ 146 | "file1.js", 147 | "file2.js" 148 | ] 149 | } 150 | ``` 151 | 152 | The following tasks are available to this list of files: 153 | 154 | * `grunt` watches LESS and JS and runs `grunt less:development`, `grunt uglify` and `grunt jshint` when files are saved 155 | * `grunt jshint` Runs JSHint on `js/dev/scripts.js` 156 | * `grunt uglify` Runs Uglify on all files specified in `js/dev/config.json` and builds to `js/scripts.min.js` 157 | * `grunt watch:js` Runs Uglify and JSHint whenever `js/dev/scripts.js` is saved with 158 | 159 | ### Contributors 160 | 161 | * Joe Ying - PHP Developer 162 | * Jeff Waterfall - Front End / Wordpress Developer 163 | * [Steve Mynett](http://twitter.com/stevemynett) - Front End / Wordpress Developer -------------------------------------------------------------------------------- /config/Vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | 5 | Vagrant::Config.run do |config| 6 | config.vm.customize ["modifyvm", :id, "--memory", 1536] 7 | config.vm.box = "wordpress-multisite" 8 | config.vm.box_url = "https://hootsuite-static-sites.s3.amazonaws.com/wordpress-multisite-vagrant-1.1.box" 9 | config.vm.network :hostonly, "192.168.37.21" 10 | config.vm.share_folder("vagrant-root","/ebs1/www/","../../www", :owner => 'vagrant', :group => 'www-data', :mount_options=>['dmode=775,fmode=775']) 11 | config.vm.share_folder("vagrant-root2", "/vagrant", "../../", :create => true) 12 | end 13 | -------------------------------------------------------------------------------- /config/grunt/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // helper function to put the theme path in front of every filename in the array 4 | appendRelativePathToScripts = function(scriptsArray) { 5 | for (var i = 0; i < scriptsArray.length; i++) { 6 | scriptsArray[i] = grunt.config.process("<%= paths.theme %>/js/dev/") + scriptsArray[i]; 7 | } 8 | return scriptsArray; 9 | } 10 | 11 | // set these two configs BEFORE initConfig so that grunt.config.process function can find the "paths.theme" variable 12 | grunt.initConfig({ 13 | paths: { 14 | theme: '/ebs1/www/wp-content/themes/hootsuite' 15 | }, 16 | }); 17 | 18 | /* 19 | This will look for a config.json file in a JS folder 20 | config.json will determine the order JS is uglified in 21 | 22 | JSON Format should be: 23 | {"files":["file1.js", "file2.js"]} 24 | */ 25 | grunt.config("config", grunt.file.readJSON(grunt.config.process("<%= paths.theme %>") + "/js/dev/config.json")); 26 | 27 | // project configuration 28 | grunt.initConfig({ 29 | pkg: grunt.file.readJSON('package.json'), 30 | paths: { 31 | // need to set this again here or else templating won't work for some reason... 32 | theme: grunt.config.process("<%= paths.theme %>") 33 | }, 34 | less:{ 35 | development: { 36 | files: { 37 | "<%= paths.theme %>/css/styles.css": "<%= paths.theme %>/css/less/styles.less" 38 | } 39 | }, 40 | production: { 41 | options: { 42 | yuicompress: true 43 | }, 44 | files: { 45 | "<%= paths.theme %>/css/styles.css": "<%= paths.theme %>/css/less/styles.less" 46 | } 47 | } 48 | }, 49 | jshint: { 50 | beforeconcat: ['<%= paths.theme %>/js/dev/scripts.js'] 51 | }, 52 | uglify: { 53 | my_target: { 54 | files: { 55 | '<%= paths.theme %>/js/scripts.min.js':appendRelativePathToScripts(grunt.config.process("<%= config.files %>")), 56 | } 57 | } 58 | }, 59 | watch: { 60 | less: { 61 | files: ['<%= paths.theme %>/css/less/*.less'], 62 | tasks: ['less:development'] 63 | }, 64 | js: { 65 | files: ['<%= paths.theme %>/js/dev/scripts.js'], 66 | tasks: ['uglify', 'jshint'] 67 | } 68 | } 69 | }); 70 | 71 | // load the plugin 72 | grunt.loadNpmTasks('grunt-contrib-less'); 73 | grunt.loadNpmTasks('grunt-contrib-watch'); 74 | grunt.loadNpmTasks('grunt-contrib-jshint'); 75 | grunt.loadNpmTasks('grunt-contrib-uglify'); 76 | grunt.loadNpmTasks('grunt-contrib-concat'); 77 | grunt.loadNpmTasks('grunt-contrib-coffee'); 78 | grunt.loadNpmTasks('grunt-contrib-compass'); 79 | grunt.loadNpmTasks('grunt-contrib-sass'); 80 | 81 | // load tasks 82 | grunt.registerTask('default', ['watch']); 83 | } -------------------------------------------------------------------------------- /config/grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WordpressGruntDev", 3 | "version": "0.1.0", 4 | "private": true, 5 | "devDependencies": { 6 | "grunt": "^0.4.4", 7 | "grunt-contrib-watch": "^0.6.1", 8 | "grunt-contrib-less": "^0.11.0", 9 | "grunt-contrib-sass": "^0.7.3", 10 | "grunt-contrib-compass": "^0.7.2", 11 | "grunt-contrib-coffee": "^0.10.1", 12 | "grunt-contrib-concat": "^0.3.0", 13 | "grunt-contrib-uglify": "^0.4.0", 14 | "grunt-contrib-jshint": "^0.9.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /www/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |