Use Composer to configure and manage a WordPress instance (including themes and plugins) that's shared with multiple sites.
- Improved directory structure
- Dependency management with Composer
- Easy WordPress configuration with environment and constants files
- Environment variables with PHP dotenv
- Enhanced security (separated web root and secure passwords with roots/wp-password-bcrypt)
- WordPress multitenancy (a single instance of WordPress core, themes and plugins serving multiple sites)
- PHP 8.1+
- Composer
$ curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer
$ composer create-project handpressed/wp-multitenancy-boilerplate:dev-main {directory}
$ cd {directory}
Replace {directory}
with the name of your new WordPress project, e.g. its domain name.
Composer will download WordPress, move it to /var/opt/wp
and then symlink /var/opt/wp
to web/wp
(see Directory Structure).
Composer will also symlink /var/opt/wp/wp-content/themes
to web/app/themes
, /var/opt/wp/wp-content/plugins
to web/app/plugins
and /var/opt/wp/wp-content/mu-plugins
to web/app/mu-plugins
.
Sites can now share this single instance of WordPress.
Open the conf/.env
file and add your new site's home URL (WP_HOME
) and database credentials (DB_NAME
, DB_USER
, DB_PASSWORD
). You can also define the database $table_prefix
(default is wp_
) if required.
Set your site's vhost document root to /path/to/{directory}/web
.
Add themes in web/app/themes
as you would for a normal WordPress install.
WordPress Packagist is already registered in the composer.json
file so any plugins from the WordPress Plugin Directory can easily be required.
To add a plugin, use composer require <namespace>/<packagename>
from the command-line. If it's from WordPress Packagist then the namespace is always wpackagist-plugin
, e.g.:
$ composer require wpackagist-plugin/wp-optimize
Whenever you add a new plugin or update WordPress core, run composer update
to install your new packages.
Themes and plugins are installed in the symlinked themes
and plugins
directories in /var/opt/wp/wp-content
and will be available to all multitenancy sites.
Note: Some plugins may make modifications to the core wp-config.php
file. Any modifications to wp-config.php
that are needed by an individual site should be moved to the site's conf/wp-constants.php
file.
Put custom core, theme and plugin constants in conf/wp-constants.php
.
├── composer.json → Manage versions of WordPress, plugins and dependencies
├── conf → WordPress configuration files
│ ├── .env → WordPress environment variables (WP_HOME, DB_NAME, DB_USER, DB_PASSWORD required)
│ ├── wp-constants.php → Custom core, theme and plugin constants
│ ├── wp-env-config.php → Primary WordPress config file (wp-config.php equivalent)
│ └── wp-salts.php → Authentication unique keys and salts (auto generated)
├── vendor → Composer packages (never edit)
└── web → Web root (vhost document root)
├── app → wp-content equivalent
│ ├── mu-plugins ↔ Must-use plugins symlinked to /var/opt/wp/wp-content/mu-plugins
│ ├── plugins ↔ Plugins symlinked to /var/opt/wp/wp-content/plugins
│ ├── themes ↔ Themes symlinked to /var/opt/wp/wp-content/themes
│ └── uploads → Uploads
├── index.php → Loads the WordPress environment and template (never edit)
└── wp ↔ WordPress core symlinked to /var/opt/wp (never edit)
└── wp-config.php → Required by WordPress - loads conf/wp-env-config.php (never edit)
↔
denotes a symlink.
$ composer create-project handpressed/wp-multitenancy-add-site {new_directory}
$ cd {new_directory}
Replace {new_directory}
with the name of your new project, e.g. its domain name.
Open the conf/.env
file and add the new site's home URL (WP_HOME
) and database credentials (DB_NAME
, DB_USER
, DB_PASSWORD
). You can also define the database $table_prefix
(default is wp_
) if required.
Set the new site's vhost document root to /path/to/{new_directory}/web
.
Added sites will use the existing WordPress instance (including themes and plugins) in var/opt/wp
.
Based on handpressed/substratum. Inspired by roots/bedrock and wpscholar/wp-skeleton.