inpsyde / vip-composer-plugin

A Composer plugin to ease deployment to wordpress.com VIP servers alongside Composer-based local development.
MIT License
12 stars 0 forks source link
ci composer-plugin continous-integration deploy deployment hacktoberfest mu-plugins vip vip-folder wordpress-folder wp wpcomvip

VIP Go Composer Plugin

PHP Quality Assurance


This package is a Composer plugin to be used in projects to be deployed on VIP Go platform and provides a CLI command with two different purposes:

  1. ease the Composer-based local environment that is compatible with the VIP Go platform
  2. ease the automatic deploy of the project on VIP Go

Quick reference

The package provides a command composer vip that can be used to both prepare a local environment and deploy to VIP Go repository.

Examples:

composer vip --local                       # prepare local environment

composer vip --deploy --branch="develop"   # deploy to VIP Go repository

Deploy command as shown above require some configuration in composer.json, at the very least the GitHub URL for the repository, that if not present in composer.json, can be passed to the command via the --git-url option.

It is important to note that composer vip command must be run after composer install|update.

Here's a one liner to both update Composer dependencies and prepare local environment:

composer update && composer vip

If this is the first time you come here, it is suggested to read below for better understand of what, how and why this command does what it does.

Skip to Command reference section for detailed documentation on the command and its available options.

Why

VIP Go platform is a managed WordPress hosting that allows to deploy to its server via a Git commit to a repository hosted on GitHub. Different branches means different environments, and master branch is for production.

The repository does not contain the full WordPress folder, but a sort of the /wp-content folder.

"Sort of" because there are some differences:

More info can be found here: https://vip.wordpress.com/documentation/vip-go/understanding-your-vip-go-codebase/

On top of that, as mentioned above, VIP Go as quite a few proprietary MU plugins that will always be loaded.

This means that to have a local environment that can be used to develop websites there's the need of:

More info can be found here: https://vip.wordpress.com/documentation/vip-go/local-vip-go-development-environment/

To have a local environment entirely based on Composer, where plugins, themes, libraries, and WordPress core are all installed via Composer, requires additional tasks on top of that:

The aim of the package is to make all these tasks as simple and straightforward as possible.

Prerequisites

For local development it is necessary:

Prepare the local installation

A folder on local environment must be dedicated to the project. The example structure is something like this:

folders structure

Structure in detail

In the structure in the image above only composer.json and vip-config/vip-config.php are mandatory, all the other folders/files are optional.

/config

The config folder that will contain the YAML files used for domain configuration, as described in VIP Go documentation.

/images

This folder contains site-wide available images, it is part of the standard VIP Go codebase.

/mu-plugins

This folder contains project-specific MU plugins. Please note that these are not the VIP Go MU plugins, but MU plugins that are specific to the project.

The standard Inpsyde process requires a different repository for each plugin/theme/library then pulled together via the composer.json in this repository. However, each MU plugin is a single PHP file, often composed of a few lines, and put each of them in a separate repository is overkill. This is why /mu-plugins folder exists: all the files contained in there will be deployed in the client-mu-plugins folder of VIP Go codebase.

/private

This folder is the equivalent of the namesake folder in VIP Go codebase. As described in VIP Go documentation this folder exists to contain files that are not web accessible but can be accessed by your theme or plugins. Typical use-cases are certificates and key files, etc.

Please note that the private folder on VIP is only readable from PHP and not writable.

/themes

This folder contains project-specific themes.

The standard Inpsyde process requires a different repository for each theme that are then pulled together via the composer.json. However, sometimes to put themes and especially child-themes in a separate repository might be overkill. This is why /themes can be used: all the files contained in there will be deployed in the themes folder of VIP Go codebase, alongside any other theme required via Composer.

/vip-config

This is where the site configuration is placed. There is a correspondent and namesake folder in VIP Go codebase that is supposed to contain a vip-config.php file, that is used to contain PHP configuration constants that in a “normal” installation would go in wp-config.php, considering that is not accessible on VIP Go.

/composer.json

This is where “the magic” happens. Composer is used to pulling together all the dependencies that will be used in the project.

Composer configuration

The composer.json is pretty standard. There are a few things that must be taken into consideration:

The whole set of settings available, with their defaults, looks like this:

{
    "config": {
        "vendor-dir": "vip/client-mu-plugins/vendor",
        "platform": {
            "php": "8.1"
        }
    },
    "extra": {
        "vip-composer": {
            "vip": {
                "local-dir": "vip",
                "muplugins-local-dir": "vip-go-mu-plugins"
            },
            "git": {
                "url": "",
                "branch": ""
            },
            "wordpress": {
                "version": "^6.2",
                "local-dir": "public",
                "uploads-local-dir": "uploads"
            },
            "plugins-autoload": {
                "include": ["*/*"]
            },
            "dev-paths": {
                "muplugins-dir": "mu-plugins",
                "plugins-dir": "plugins",
                "themes-dir": "themes",
                "languages-dir": "languages",
                "images-dir": "images",
                "vip-config-dir": "vip-config",
                "config-dir": "config",
                "private-dir": "private"
            },
            "custom-env-names": [
            ]
        }
    }
}

The config object is part of Composer schema, and not specific of this plugin. It is shown above for completeness. The config.platform is set above to 7.3 because that's the version used on VIP Go platform at the moment of writing, and setting this will help in getting same dependencies that will be deployed even running a different PHP version locally.

Because all vip-composer configuration is optional, if what shown above is fine for you, there's no need to add any configuration at all, because these defaults will be used in absence of configuration.

Configuration in detail

vip-composer.vip

One of the things that the command provided by this plugin do is to create a folder that mirrors the structure of VIP Go repository. This folder will be located in the root of the project folder.

vip-composer.vip.local-dir config controls the name of that folder.

Another thing that the plugin command does is to download VIP Go MU plugins, and make them usable in local WordPress installation.

vip-composer.vip.muplugins-local-dir configuration controls the name of folder where those MU plugins will be downloaded (inside project root).

vip-composer.git

This object controls the Git configuration for VIP Go GitHub repository. As shown above, default settings are empty, this requires that both URL and branch must be passed as options to composer vip command.

Might be a good idea to at least fill in the URL to avoid having to type long commands.

Note: the URL must be provided in the HTTPS format (because easier to validate), even if the command (if possible) will use SSH to interact with GitHub.

vip-composer.wordpress

When the composer vip command runs to setup local environment it installs WordPress. This configuration object controls the target location and the version that will be installed.

vip-composer.wordpress.version controls the installed version. If this is empty, the plugin will look into require object to see the version of packages with type wordpress-core and will use the version of the first package found with that type. This configuration accepts any of the format accepted by Composer package links, plus "latest", to always get the latest version.

vip-composer.wordpress.local-dir controls the folder, inside project root, where WordPress will be installed. Note that this folder (and not the project root) must be set as the webroot in the local environment web server.

vip-composer.wordpress.uploads-local-dir controls the folder, inside project root, where the "uploads" folder will be located. The uploads folder, in facts, is located outside the WordPress folder to make the WordPress folder completely disposable without losing the media. The folder will be symlinked by the plugin command into /wp-content/uploads so WordPress will work with no issues.

vip-composer.plugins-autoload

VIP suggests to load plugins via code using wpcom_vip_load_plugin function (see VIP documentation for details).

An excerpt:

we recommend loading your plugins from code. Loading plugins in code results in more control and a greater consistency across your production, non-production environments, and local development environments.

This package, by default, creates a loader MU plugin that uses wpcom_vip_load_plugin to load plugins via code as suggested by VIP.

However, in multisite installations, it might be desirable to have some plugins activated in only some of the sites, and this is not possible when loading plugins via wpcom_vip_load_plugin.

Thanks to plugins-autoload setting it is possible to select which plugins will be autoloaded via either a deny-list (list of plugins to don't autoload) or a allow-list (list of plugins to autoload).

Without any setting the default is "autoload everything".

To control which plugins to include it is possible to list them, eventually with * as wildcard, e. g.:

{
    "extra": {
        "vip-composer": {
            "plugins-autoload": {
                "include": [
                    "foo/some-package",
                    "bar/*",
                    "baz/something-*"
                ]
            }
        }
    }
}

In the case it is easier to exclude packages from being loaded, it is possible to use the exclude key:

{
    "extra": {
        "vip-composer": {
            "plugins-autoload": {
                "exclude": [
                    "foo/some-package",
                    "bar/*"
                ]
            }
        }
    }
}

To be noted:

vip-composer.dev-paths

As shown above in the Prepare the local installation section, in the root of the project folder there might be some folder for themes, plugins, MU plugins that can be used to include those things in the same repository of the project, without using a separate repository for them. Moreover, there are folder like config, private and images that can be used to fill the related VIP folder.

Only the config/vip-config.php is mandatory all the other folders and their content is optional.

vip-composer.dev-paths controls the name of those folders. By default names are the same names used by VIP Go repository, except for mu-plugins/ is renamed to client-mu-plugins/.

vip-composer.custom-env-names

VIP expects WordPress configuration normally placed in wp-config.php (e.g. constants with secrets) to be placed in a vip-config.php file. To help having environment-specific setting, this package support multiple files where to set such configuration, where each file is environment-specific and named after the environment. The configuration files can be placed directly in the ./vip-config/ folder in a "website repository" root folder, or can be placed in separate Composer packages having the vip-composer-plugin-env-config type, whose support is handled by this package. In the latter case, the supported files that are copied over from packages into website config folder are, by default, those named after the environments supported by WordPress core, and they are: local.php, development.php, staging.php, and production.php, plus a file named all.phpaimed at target all environments. Considering VIP GO allows us to have more environments or anyway name them differently, it is possible to expand the list of supported files names via the vip-composer.custom-env-names configuration.

Folder structure after the command runs

Assuming default configuration and a folder structure like the one shown in the screenshot under the Prepare the local installation section, after running:

composer update && composer vip --local

(and waiting for a while) the structure of the project folder will be:

folder structure after vip command

Files and folder created by the command have been highlighted above in light yellow. Let's list them:

/public

This is the project web-root, and it contains a standard WordPress installation.

Note: in the image all the WordPress root files except index.php (wp-load.php, wp-login.php, etc...) have been removed for readability’s sake.

/uploads

This folder will contain all the media files uploaded locally in WordPress. The folder is located outside the /public folder to make the latter entirely disposable. However, because /public folder is the web-root, /uploads folder is symlinked to /public/wp-content/uploads that is the standard WordPress uploads folder, so as long as WordPress (and the web-server) are concerned uploads can be served correctly.

Especially relevant for Linux users: make sure the folder is writable by the local web-server and PHP.

/vip

This folder contains the exact 1:1 representation of the VIP Go repository. It contains exactly the files that will be pushed to the VIP Go repository for the project. More on this folder in next section.

/vip-go-mu-plugins

This folder contains VIP Go MU plugins. In the wp-config.php file that is also generated, this folder is already configured as the WordPress WPMU_PLUGIN_DIR so that locally WordPress will correctly load all the VIP MU plugins.

/composer.lock

The Composer lock file.

Those familiar with Composer could wonder where the Composer "vendor" folder and the Composer autoload file are located.

The answer is: inside /vip/client-mu-plugins. As written above, the /vip folder contains exactly what will be pushed to the VIP Git repository, and because for sure we need Composer libraries and autoload online, we need those to be inside the /vip folder.

/wp-cli.yml

WP CLI config file. It contains a reference to the WordPress installation path, so WP CLI commands can be executed from the project root folder without having to pass the --path parameter all the time.

/wp-config.php

WordPress' configuration file for the local environment. This is slightly different from a "standard" wp-config.php because it contains

The first time the VIP Go Composer plugin is executed there's the need to fill it with project settings, e. g. DB settings, nonce keys and such.

/vip folder in detail

Let's "zoom" in the /vip folder:

/vip folder internal structure

/client-mu-plugins

This folder contains the Composer /vendor folder, including the autoload.php file. This is a "standard" Composer vendor folder, and it is located here thanks to the config.vendor-dir configuration added in composer.json.

This folder also contains a copy of all MU plugins available in /mu-plugins folder.

Finally, it contains the __loader.php file, a MU plugin generated by the composer vip command that contains instructions to:

/config, /images, and /languages

This folder contain a copy of any file located in the namesake folders under root. In the example above these folders are empty because the correspondent folders under root are empty or do not exist at all.

/plugins

This folder contain all the plugins that have been required via Composer (in the example, just one), plus a copy of any plugin located in /plugins folder under root (in the example that folder does not exist at all).

/private

This folder will contain a copy of any file located in /private folder under root (in the example that folder does not exist at all) plus a deploy-id file, a text file that contains a random UUID that is unique per build (and so per deployment). It can be used by application code, for example, to bust caches so that at every deploy caches are invalidated.

/themes

This folder contain all the themes that have been required via Composer (in the example, just one), plus a copy of any plugin located in /themes folder under root (in the example there's a child theme).

Please note that even if this approach is supported, it is suggested to use separate repositories for themes, due to an issue with "dev paths" using sub-folders, and themes always comes in a folder.

Make sure to review the section Managing Dev Paths below that documents this matter in detail.

/vip-config

This folder contain a copy of any file located in /vip-config folder under root, at the very least the vip-config.php file that is required.

Dev paths

In the section right above has been said how the folders /client-mu-plugins, /config, /images, /languages, /plugins, /themes, and /vip-config, all might contain copies of files and folders located at the root of the package. The reason for this is to make the /vip folder an exact 1:1 representation of what will be deployed to VIP, but there are some gotchas associated with this approach.

Make sure to review the section Managing Dev Paths below that documents this matter in detail.

A .gitignore sample

It is important that new files generated by both Composer and this plugins needs to be git-ignored.

An example of .gitignore could be the following:

/public/
/uploads/
/vip/
/vip-go-mu-plugins/
/wp-config.php

but note that this is not generated automatically.

Local Development Workflow

Having a local environment up and running is just the start of the development process.

The workflow of development will be:

  1. create a new repository for each theme/plugin/library that has to be used in the project
  2. push it to a remote VCS service (GitHub, BitBucket, GitLab...)
  3. add it as a dependency to the project's composer.json
  4. run composer update && composer vip --local to update the dependencies and refresh the local environment

Having to deal with remote repositories for each plugin/theme/library might be overkill, especially in the very early stages of development.

Local Development with Composer Studio

It is much better to deal with local repositories during development. It has been said how for simple and/or project specific MU plugins/plugins/themes it is possible to use "dev paths" for the scope, but very likely there will be the need to work on packages that need to live in separate repositories.

Luckily Composer supports "path repositories".

In short, instead of using a VCS repository "as source" for a package, Composer can use a local path (even relative) so that it is possible to run composer install and get the content of that folder installed just like any other remotely-hosted package.

The nice thing about it is that the local folder used as path repository could be very well the local clone of a remote repository, so that when changes are finalized and tested locally (thanks to path repository) they can be pushed to the remote repository to have them deployed online.

The bad thing about it is that using path repositories requires changing the composer.json and that's not an option, because it does not make sense to place local paths in a composer.json that is pushed online.

To solve this problem it is possible to make use of Composer Studio, a Composer plugin that allows the usage of Composer path repositories without changing the composer.json, but making use of a separate studio.json file that can be easily git-ignored and so kept local.

Command reference

As quickly written in the beginning, this plugin provides a single command:

composer vip

Options Cheat-Sheet

In detail

Local

--local option makes the command perform a set of tasks to prepare and/or update the local environment:

  1. Download WP core if necessary
  2. Create and configure wp-config.php if necessary
  3. Download VIP Go MU plugins if necessary
  4. Generate a loader file to require Composer autoloader and eventual MU plugins from sub-folders
  5. Symlink "content" folders into WordPress installation
  6. Copy "dev paths" into VIP folder
  7. Create and configure wp-cli.yml if necessary

This is the default option and it is assumed if no option is passed.

Deploy

--deploy option makes the command perform a set of tasks to prepare, sync and update the VIP Go GitHub repository:

The command using this option is perfectly suitable to be run in CI pipelines.

Git configuration

Two commands options are available to configure Git operations:

Example:

composer vip --deploy --git-url="https://github.com/wpcomvip/my-project" --branch="develop"

Git options for local environment

By default, when --local option is used the plugin prepare the local environment without bother with Git at all. Sometimes might be desirable to look at the Git diff of what would be pushed using --deploy, before actually doing the deploy.

This could be achieved via the --git option.

When this option is used, the plugin creates a folder inside /vip that has an unique name prepended by a dot, something like /.vipgit5b59852eb21c7.

This folder will be a Git repository, build from VIP Go GitHub repo, where all changes have been committed. So by pointing a Git client / tool to this folder it is possible to "preview" changes before pushing. And, actually, by running git push on this folder it is possible to deploy the changes.

Sometimes it is also desirable to directly push the changes from local environment.

This could be achieved via the --push option. Using this option in combination with --local is different than just using --deploy by the fact that the latter will only run tasks that are relevant for remote server (e. g. always skipping WP install, VIP MU plugins download...) so it is a good choice to deploy from a CI. By using --local --push the command will update the development environment and also push changes to remote repo.

Git configuration (URL and branch) applies when using either --git or --push in the same way they do when using --deploy.

Example:

composer vip --local --git --branch="develop"

Managing Dev Paths

One of the things that it seems harder to grasp about the folder structure promoted by this plugins is why there are "dev paths" (plugins, themes, config and all the other folders in VIP Go structure) in the root of the project and same folders are also copied under /vip folder.

The reason is quite simple. The reason to exist of /vip folder is to be a 1:1 mirror of the VIP Go Git repository.

Which means that when using Composer, a folder like /vip/plugins will contain plugins that are installed via Composer. Same for themes and MU plugins.

If, for any reason, developers want to use the same "project" repository to include plugins, MU plugins, themes without them being on a separate repo, it would mean that /vip/plugins (or /theme or /client-mu-plugins) would contain, after composer install, a "mix" of third party dependencies required via Composer and custom packages written for the project.

Because the latter should be surely kept under version control, while the former probably not, it would be necessary to rely on quite complex (and honestly hard to maintain) .gitignore configuration.

By using separate folders, like this plugins does, the folders in root contain only custom work to be kept under version control, and then the command takes care of copying them, alongside other dependencies that Composer takes care of placing in proper place (thanks to a custom installer shipped with the plugin).

This way the /vip folder can be completely Git-ignored and it also becomes completely disposable, which is a good things for folders that are automatically generated.

However, this approach has also two issues.

The first issue is that "dev paths" in root folder are "copied" into /vip folder, which means that at any change the copy has to be done again.

This is why the plugin command provides the option --sync-dev-paths.

This flag must be used as the only flag, and makes the command sync the dev paths from root to /vip.

Example:

composer vip --sync-dev-paths

Considering this is a quite fast operation it makes sense to use (if possible) IDE feature that automatically run the above command when anything changes inside "dev paths".

Here's the screenshot on how this could be set up via in PHPStorm using a "file watcher":

File watcher setup in PHPStorm

The second issue regards themes and plugins that comes in own folder. The problem is that when a theme or a plugin in own folder is deleted from /themes or /plugins, it will not be deleted from /vip/themes or vip/plugins.

For example, if there's a theme in /themes/my-theme, its files will be correcly kept in sync with /vip/themes/my-theme as long as the /themes/my-theme exists. However, if /themes/my-theme is deleted, /vip/themes/my-theme will not be deleted.

This issue does not affect single-file plugins, e. g. a plugin located at /plugins/my-plugin.php will be correcly kept in sync with /vip/plugins/my-plugin.php and if /plugins/my-plugin.php is deleted, /vip/plugins/my-plugin.php will be deleted as well.

For this reason it is suggested to use "dev paths" only for MU plugins and simple single-file plugins, but use a separate repository for themes (that always comes in own folder) or more complex plugins.

Force or skip WP download

One of the things the command does when using --local is to download WordPress from official release zip file ("no content" version).

This is done in 3 cases:

This means that even if a newer version of WordPress is released that would satisfy the requirements, but the currently installed version also satisfy the requirements no installation is made.

For example if the requirements says 4.9.* and the installed version is 4.9.5 but the 4.9.7 is available, WordPress is not updated by default when --local option is used.

In this case an update can be forced by using --update-wp flag.

This flag can be used in combination with --local to mean "update local environment and also force the update of WP if a new acceptable version is available" or it can be used alone to mean "just update WP and nothing else".

This latter usage is worthy because, as previously said, when using this plugin, composer update does not update WordPress.

Another option that controls the download of WordPress is --skip-wp.

This option tells the command to never download WP. Can only be used in combination with --local. This is useful when, for example, version requirements is set to "latest" but one wants to save the time necessary to download and unzip WordPress (which might take a while, especially on slow connections).

Must be noted that if WordPress folder is not there and --skip-wp is used, the local installation will not functional.

It is also worth saying that if used together --update-wp and --skip-wp will make the command fail.

Example:

composer vip --update-wp

Update or skip VIP Go MU plugins download

The most time-consuming task the first time command is ran is to download VIP Go MU plugins. Those plugins accounts for over 300 Mb in total, pulled from a repo with several recursive sub-modules.

This is why the composer vip command by default only download the MU plugins if they are not there. So presumably the first time ever the command is ran, or if the folder is deleted by hand.

However, those MU plugins are actively developed, and it make sense from time to time update them locally to be in sync with what is on VIP Go servers.

This can be obtained via the --update-vip-mu-plugins flag.

This flag can be used in combination with --local to mean "update local environment and also force the update of VIP Go MU plugins" or it can be used alone to mean "just update VIP Go MU plugins".

The latter usage is basically an alias for:

git clone --recursive git@github.com:Automattic/vip-go-mu-plugins.git

but:

composer vip --update-vip-mu-plugins

is shorter to type and easier to remember.

Another option that controls the download of Vip Go MU plugins is --skip-vip-mu-plugins.

This option tells the command to never download VIP Go MU plugins. Can only be used in combination with --local. This is useful when MU plugins are not there (never downloaded or deleted by hand), but one wants to save the time necessary to download them, for any reason.

Must be noted that if MU plugins are not there and --skip-vip-mu-plugins is used, the local installation will not be functional.

It is also worth saying that if used together --update-vip-mu-plugins and --skip-vip-mu-plugins will make the command fail.

Example:

composer vip --local --update-vip-mu-plugins

VIP dev-env

VIP dev-env simulates the VIP environment using Docker and Lando.

For this reason, while it is a local development environment has many characteristics of the production environment. The --vip-dev-env flag for the command, executes all the steps that are necessary to prepare the vip/ folder, including the production autoload, skipping operations like the download of WordPress core or VIP MU plugins because those are handled by the vip dev-env create command.

Example:

composer vip --vip-dev-env
vip dev-env create --app-code="./vip"

License and Copyright

VIP Composer Plugin is a free software, and is released under the terms of the MIT license. See LICENSE for complete license.

The team at Syde is engineering the Web since 2006.