In this article, we will talk about how to install WordPress via Composer. Let’s go through step by step how to do it. Let’s consider the options of installing WordPress in a separate directory and the classic option with a standard file structure.
There are a number of benefits to using Composer for your WordPress installation:
- It’s convenient to update WordPress
No more copying files if you have disabled WP update via the admin panel. To change the WordPress version, we only need to change the WordPress version number in thecomposer.json
file and run the console commandcomposer install
. - Flexibility to change WordPress version
Forget about upgrading to only thelatest
version of WordPress. With Composer, you can specify any version of WordPress you want, whether it’s a patch, minor or major version. - Simple Code Review
Forget about thousands of lines of changes in PullRequest when you update WordPress. Your colleagues will only see the WordPress version change lines incomposer.json
andcomposer.lock
. - WordPress core files will never be modified
Core files, by accident or on purpose, can never be modified and committed into the GIT. WordPress will be installed via Composer. You will always be sure that a new version of WordPress was obtained from the official repository without modification. - Smaller repository size
When using Composer, WordPress core files will not be stored in the repository. This will reduce the size of the repository, which will favorably affect repository cloning and deploys. - Using different versions of WordPress in a mono repository.
Installing WordPress via Composer can help us with this too, but this solution is beyond the scope of this article.
In order to start installing WP via Composer, you need to do some configuration of the project, which is described below.
About Composer
The Composer is a PHP dependency management tool. It allows you to declare the libraries your project depends on and will manage (install/update) the dependencies instead of you. The Composer also provides proper solving of library dependency conflicts.
For using Composer locally there are 2 options:
- Use the official documentation with the Composer binary installed locally https://getcomposer.org/download/
(This option is preferred if you have not worked with Docker before) - Work with the Composer by using a Docker Container (following instructions README.md)
Next, let’s talk about installing WordPress via Composer.
Install WordPress via Composer
To install WordPress via Composer, we first need to create a composer.json
file in the root of the project.
You can do this using the composer init
command or create the file manually by pasting the example of code below into composer.json
:
{
"name": "wp-yoda/composer-with-wordpress",
"description": "Example of using Composer for installing WordPress core and plugins",
"require": {}
}
Next, we need to add the repositories
directive to composer.json
.
What is the repositories directive in composer.json
A Repository in Composer is the source of the package. When installing packages, Composer will look in all repositories in the composer file to find the required package for the project.
By default, only the Packagist.org repository is registered in Composer. But you can add more repositories for your project by declaring them in the repositories directive of thecomposer.json
file.
Read more about Composer’s repository at the link
The composer.json
file will look like this:
{
"name": "wp-yoda/composer-with-wordpress",
"description": "Example of using Composer for installing WordPress core and plugins",
"repositories": [
{
"type": "package",
"package": {
"name": "wordpress/wordpress",
"version": "6.2.2",
"type": "wordpress-core",
"dist": {
"type": "zip",
"url": "https://github.com/WordPress/WordPress/archive/refs/tags/6.2.2.zip"
}
}
}
],
"require": {}
}
Now when you plug in the wordpress/wordpress
package. The composer will find the package in the added repository and install it.
There is no official WordPress package on packagist.org at this moment
It is not recommended to use unofficial WordPress packages likejohnpbloch/wordpress
orroots/wordpress
. The authors’ repositories can be hacked, code changed, package updated and the sites that use them will be infected.
The most reliable way to install WordPress via Composer at the moment is the way described in the article – connecting the official WordPress GH repository tocomposer.json
.
Once we have added the source from where WordPress will be downloaded (the official repository), I suggest adding WordPress as a Composer dependency.
Let’s run the following command in the terminal:
composer require wordpress/wordpress
The composer will plug the package wordpress/wordpress
into composer.json
with this command and install it into our project in the ./vendor
directory.
You should see the following file structure:
Remember to add/vendor/
to the.gitignore
file so that the/vendor
directory files are not indexed by GIT.
Now our project has WordPress installed, but it is in the vendor
directory, to make our project work it needs to be moved to another location. But where?
There are 2 ways you can do this:
The classic WordPress structure
.
├── index.php
├── composer.json
├── composer.lock
├── vendor/
│ ├── autoload.php
│ └── ......
├── wp-admin/
│ ├── about.php
│ ├── admin-ajax.php
│ ├── admin-functions.php
│ └── ......
├── wp-content/
│ ├── mu-plugins/
│ ├── plugins/
│ ├── themes/
│ └── uploads/
├── wp-cron.php
├── wp-config.php
├── wp-includes
│ ├── admin-bar.php
│ ├── author-template.php
│ ├── block-editor.php
│ ├── block-i18n.json
│ ├── block-patterns/
│ ├── block-patterns.php
│ ├── block-supports
│ ├── block-template-utils.php
│ ├── block-template.php
│ ├── wp-db.php
│ └── ......
├── wp-links-opml.php
├── wp-load.php
├── wp-login.php
├── wp-mail.php
├── wp-settings.php
├── wp-signup.php
├── wp-trackback.php
└── xmlrpc.php
WordPress in a separate directory
.
├── index.php
├── composer.json
├── composer.lock
├── vendor/
│ ├── autoload.php
│ └── .....
├── wp/
│ ├── index.php
│ ├── wp-activate.php
│ ├── wp-admin/
│ ├── wp-blog-header.php
│ ├── wp-comments-post.php
│ ├── wp-config-sample.php
│ ├── wp-cron.php
│ ├── wp-includes/
│ ├── wp-links-opml.php
│ ├── wp-load.php
│ ├── wp-login.php
│ ├── wp-mail.php
│ ├── wp-settings.php
│ ├── wp-signup.php
│ ├── wp-trackback.php
│ └── xmlrpc.php
├── wp-config.php
└── wp-content/
├── mu-plugins/
├── plugins/
├── themes/
└── uploads/
You’ll know which approach will suit you better when you read about both options in the article.
First, let’s look at installing WordPress via Composer with a classic file structure.
Install WordPress with a classic file structure
The classic WordPress structure of a project – is a variant where we place all WordPress core files in the root of the project, along with the project files. There is no separation between the WP core and the code we write.
This option has its own advantages and disadvantages.
Advantages:
- All plugins are compatible with this project structure as it comes out of the box.
- It requires no additional configuration of directory and URL constants.
- You can implement it with an existing project without fear of breaking something. Since the structure of files and directories is not changed.
Disadvantages:
- The WordPress core files are mixed with the project files, which makes it difficult to work with the project.
Configuring composer.json
To move the directory from vendor
to the root directory of the project we will use Composer Script events.
Composer scripts events are Composer events that run custom commands before/after Composer commands are executed. For example you can run a command aftercomposer install
.
You can read more at the link.
Add scripts
directive to composer.json
with post-install-cmd
event that fires after composer install
.
"scripts": {
"post-install-cmd": "cp -r ./vendor/wordpress/wordpress/* ./"
}
In the"post-install-cmd"
event, we copy the contents of the installed WordPress fromvendor
directory to our working directory./
Now run the command in the terminal:
composer install
After that, we can see the WordPress files in our project. Now let’s add the core files to .gitignore
to keep them out of the repository and see in the GIT index only our project files.
Setting up .gitignore
To keep core files out of the GIT index, you should add the following rules to .gitignore
.idea
/vendor/
# ignore WordPress files
/index.php
/license.txt
/readme.html
/wp-activate.php
/wp-blog-header.php
/wp-comments-post.php
/wp-config-sample.php
/wp-config.php
/wp-cron.php
/wp-links-opml.php
/wp-load.php
/wp-login.php
/wp-mail.php
/wp-settings.php
/wp-signup.php
/wp-trackback.php
/xmlrpc.php
/wp-includes
/wp-admin
/wp-content/*
!/wp-content
/wp-content/plugins/*
!/wp-content/plugins/
!/wp-content/plugins/YourCustomPluginName
/wp-content/themes/*
!/wp-content/themes/
!/wp-content/themes/YourCutsomTheme
Now the core files will not be indexed.
In order to add a new plugin or theme to the repository, you need to add lines to the end of the .gitignore
file to exclude new themes or plugins from being ignored by example:
# new plugin
!/wp-content/plugins/YourCustomPluginName
# new theme
!/wp-content/themes/YourCutsomTheme
Where YourCustomPluginName
or YourCustomTheme
is the directory name of your WP plugin or theme.
Source code
The source code of the WordPress installation with the classic structure is available via a link on GitHub. You can deploy it locally by following the instructions in README.md
.
Install WordPress in a separate directory
Installing WordPress in a separate directory is a variant of installing WordPress via Composer where we place all the core files in a separate directory, away from the project files.
.
├── index.php
├── composer.json
├── composer.lock
├── vendor/
│ ├── autoload.php
│ └── .....
├── wp/
│ ├── wp-activate.php
│ ├── wp-admin/
│ ├── wp-blog-header.php
│ ├── wp-includes/
│ ├── wp-load.php
│ └── .....
├── wp-config.php
└── wp-content/
├── mu-plugins/
├── plugins/
├── themes/
└── uploads/
This option has its advantages and disadvantages. Let’s talk about them.
Advantages:
- Convenient code structure, nothing gets in the way and does not distract you from development. You work only with the
./wp-content
directory, themes, and plugins, the core files do not distract you when working, because they are hidden in the./wp
directory. - In case the WP core is stored in a separate directory, updating it is less painful as you only need to replace the core files in the
./wp
directory. There is no chance to overwrite project files (Themes, Plugins) with kernel files.
Disadvantages:
- Some plugins that are “not written according to WP standards” may not work due to hard-coded paths relying on the “classic project structure”.
- You need to configure constants
wp-config.php
in WordPress, to get WordPress URLs and paths to the correct directories. - You need to add the
index.php
file to the root of the project.
Let’s move on to configuring composer.json.
Configuring composer.json
What are Composer Scripts – I described in the classic WordPress installation variant in this article.
To use this option, you need to add the scripts
directive with a post-install-cmd
event that fires after install
:
"scripts": {
"post-install-cmd": "mkdir -p ./wp && cp -r ./vendor/wordpress/wordpress/* ./wp"
}
In the script "post-install-cmd"
we copy the contents of the installed WordPress from the vendor
directory to the ./wp
directory. The WordPress core will be stored in the ./wp
directory.
Now we can perform a WordPress installation through Composer:
composer install
and you’ll see a ./wp
directory in the root of your project with the WordPress core.
Configuring .gitignore
To keep kernel files out of the GIT index, you should add the following rules to .gitignore
.idea
/vendor/
# ignore WordPress files
/wp
/wp-content/*
!/wp-content
!/wp-content/index.php
!/wp-content/mu-plugins/
!/wp-content/plugins/
!/wp-content/themes/
After adding these lines, WordPress core, cache in wp-content, uploads and other WordPress system files will not be indexed.
If you want to add a file or directory from wp-content to the GIT index, simply exclude that directory from.gitignore
with a!
sign in front of that directory:!/wp-content/new-directory/
Let’s go to add an index.php
.
Add index.php
Since our core is in the wp
directory, we do not have an index.php
file in the root of the project. Hence WP core will not be loaded for client requests. Because of the absence of the index.php
main file.
Let’s create the index.php
file and add the following code to it:
<?php
define( 'WP_USE_THEMES', true );
/** Loads the WordPress Environment and Template */
require __DIR__ . '/wp/wp-blog-header.php';
This standard index.php
file from WP with one exception, we changed the path to the file wp-blog-header.php
to the file into the wp
directory.
Let’s move on to creating the wp-content/
directory and customizing it.
Add the wp-content directory
The WordPress core is located in the directory ./wp
, and developed themes and plugins will be located inside ./wp-content
.
For this structure we need to create a directory ./wp-content
in the root of the project, with the following contents.
.
├── wp/
└── wp-content/
├── index.php
├── mu-plugins/
├── plugins/
├── themes/
└── uploads/
You can copy wp-content
from the ./wp
directory and paste it into the root of your project, deleting all the unnecessary stuff.
Now you can add the plugins and themes you need to ./wp-content/themes
or ./wp-content/plugins
.
After adding the wp-content
directory, we need to set the correct constants for WordPress.
Let’s write constants with URLs and paths
In order for WordPress to understand what URLs and paths the WordPress core and wp-content
directory are located at we need to set constants with the correct values.
But before that, we need to create a wp-config.php
file in the project root.
To do this, we can copy wp-config.php
from ./wp/
to the project root with the name wp-config.php
.
Once wp-config.php
is created, add the following constants to the end of the wp-config.php
file, but before the line require_once ABSPATH . 'wp-settings.php';
define( 'WP_HOME', 'http://' . $_SERVER['HTTP_HOST'] ); // Site URL for the front-of-site
define( 'WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST'] . '/wp' ); // URL address with WP core (which is for the admin)
define( 'WP_CONTENT_DIR', __DIR__ . '/wp-content' );
define( 'WP_CONTENT_URL', WP_HOME . '/wp-content' );
WP_SITEURL
andWP_HOME
override the value ofsiteurl
andhome
option in thewp_options
table respectively. But they do not change these values in the database.
*siteurl
– is the URL where the WordPress core is located.
*home
– is the URL of the site (front-end).
You can read more at wp-kama at this link
TheWP_CONTENT_DIR
andWP_CONTENT_URL
consts are needed to specify the path to the./wp-content
directory in our project, since WordPress core has been placed in the./wp
.
If we don’t specify these constants, WP will look for wp-content in the./wp
directory.
When you go to the site you should see the following error
This will mean that you need to fill database connection constants in wp-config.php
. Once you have filled this in, go to the admin panel and activate the added theme in the admin area.
The admin panel is available at /wp/wp-admin
Source code
The full code for Installing WordPress in a separate directory is available in the repository via the link on GitHub.
Summarizing
Which option is more suitable is of course up to you. If you have a well-established project that has been developing for many years, and you are not the developer who has been running it since its inception, then I would not recommend you to switch to the “Install WordPress via Composer in a separate directory” option. It’s better to consider the “Install WordPress with Classic File Structure” option. In this case, you have no risk of breaking anything.
While the option of “Install WP via Composer in a separate directory” is more suitable for new projects. With it, you will be able to limit a more convenient file structure of the project without fear of breaking it.
Don’t hesitate to tell your colleagues about this approach and apply it to projects.
This is the first article in a series of two articles Using Composer in WordPress.
The second article about installing plugins via WordPress will be published a bit later.