Install WordPress via Composer

Install WordPress via Composer

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 the composer.json file and run the console command composer install .
  • Flexibility to change WordPress version
    Forget about upgrading to only the latest 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 in composer.json and composer.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 the composer.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 like johnpbloch/wordpress or roots/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 to composer.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:

Install WordPress via Composer
inside the ./vendor/wordpress directory will be the core of WordPress

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 after composer 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 from vendor 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 and WP_HOME override the value of siteurl and home option in the wp_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

The WP_CONTENT_DIR and WP_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

Install WordPress via Composer

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.




Андрей Писаревский

Author: Andrei Pisarevskii 

PHP | WordPress Team Lead. I have commercial programming experience since 2010 and expertise in the full cycle of web development: Frontend, Backend, QA, Server administration, managing large teams and Enterprise projects.

Leave a Reply

Your email address will not be published. Required fields are marked *