Skip to content
KntntPublic

About

Bash script to quickly and easily create local WordPress sites.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

101 Commits

Folders and files

Repository files navigation

mkwp - make wordpress

Bash script to quickly and easily create local WordPress sites.

Installation

mkwp is a single file. Download it from the latest release into a directory on your PATH, such as ~/bin, and make it executable:

mkdir -p ~/bin
curl -fsSL https://github.com/Kntnt/mkwp/releases/latest/download/mkwp -o ~/bin/mkwp
chmod +x ~/bin/mkwp

To update mkwp, run the same commands again. To install a particular version, put download/v<version> in place of latest/download in the link, as in https://github.com/Kntnt/mkwp/releases/download/v1.9.0/mkwp. The first line of mkwp --help shows the installed version.

Install the file from a release, not from a clone of the repository. The version is written into the file when a release is built, so a copy of mkwp taken straight from the repository has none and calls itself unreleased. To build the file from a clone, run bin/build-release-assets: it writes release-assets/mkwp, with the version taken from git.

mkwp needs a running Docker provider and DDEV on your PATH. To build a site from a blueprint, it also needs jq, which current macOS comes with.

Usage

NAME
	mkwp <version> - make wordpress

SYNOPSIS
	mkwp [OPTION]... NAME
	mkwp --destroy NAME

DESCRIPTION
	Makes a local WordPress site with the domain name.ddev.site where
	name is the domain name provided as the argument [NAME].

	The site can be described by a blueprint, a JSON file given with
	-B or --blueprint. See BLUEPRINT below.

	Your personal settings, and the blueprint to use when none is given
	with -B, can be kept in a configuration file. See CONFIGURATION
	below.

	An option given on the command line always takes precedence. If a
	site setting (title, language, PHP or WordPress version, Redis or
	database server) is not given there, it is in the first place set to
	the value in the blueprint, if there is one and it has the setting,
	and in the second place to a default value. If a personal setting
	(email, user, password or directory) is not given there, it is in
	the first place set to the value in the configuration file specified
	with -c or --config, in the second place to the value in the
	configuration file ~/.mkwp, and in the third place to a default
	value.

OPTIONS
	-t <title>
	--title=<title>
		The title of the WordPress site. If omitted, [NAME] will be
		used.

	-d <path>
	--directory=<path>
		The home directory of the website. If omitted, current
		directory will be used as home directory.

	-D <dirname>
	--dirname=<dirname>
		The name of the directory the site is created in, underneath the
		home directory. If omitted, [NAME] will be used.

	-m <email>
	--email=<email>
		The email address of the first user created in WordPress. If
		omitted, the current username is used as local-part and the
		hostname as domain.

	-u <username>
	--user=<username>
		The username of the first user created in WordPress. If
		omitted, the local-part of the email address will be used.

	-p <password>
	--password=<password>
		The password of the first user created in WordPress. Must at
		least be 12 characters long. If omitted, a 16 character random
		password is generated.

	-l <locale>
	--language=<locale>
		The language of the WordPress site. If omitted, en_US will be
		used. For a number of well-known locales, the site timezone is
		set accordingly (e.g. Europe/Stockholm for sv_SE).

	-T <themes>
	--themes=<themes>
		Comma separated list of themes to install. For a theme hosted
		on WordPress.org, enter its slug or URL to its zip-file. For a
		theme hosted in a remote Git repository, enter its remote URL.
		For a theme hosted locally, enter the path to the zip file. The
		last listed theme is activated. If omitted, WordPress's current
		default theme will be used.

	-P <plugins>
	--plugins=<plugins>
		Comma separated list of plugins to install. For a plugin hosted
		on WordPress.org, enter its slug or URL to its zip-file. For a
		plugin hosted in a remote Git repository, enter its remote URL.
		For a plugin hosted locally, enter the path to the zip file.

	-M <plugins>
	--mu-plugins=<plugins>
		Comma separated list of mu-plugins to install. For each plugin,
		provide the plugin's URL from where it can be downloaded as
		php-file (e.g. https://raw.githubusercontent.com/Kntnt/kntnt-
		adminbar-sanitizer/master/kntnt-adminbar-sanitizer.php).
		If omitted, no mu-plugins will be installed.

	-V <version>
	--php=<version>
		Version of PHP to be used. If omitted, PHP 8.5 will be used.

	-W <version>
	--wp=<version>
		Version of WordPress to install, given as <major>,
		<major>.<minor> or <major>.<minor>.<patch> (e.g. 6, 6.9 or
		6.9.4). Omitted parts are resolved to the highest available
		release. If omitted entirely, the latest version is installed.
		The core auto-update policy reflects the precision: a full
		<major>.<minor>.<patch> disables auto-updates, while <major> or
		<major>.<minor> enables patch-level updates only.

	-R
	--redis
		Adds a Redis service to the site and enables it as WordPress
		object cache backend: the Redis Object Cache plugin is
		installed and activated, and its object-cache.php drop-in is
		enabled.

	--db-server=<type>:<version>
		The database server of the site, given as mariadb:<version> or
		mysql:<version> (e.g. mariadb:11.8), with a version that DDEV
		has. If omitted, DDEV's default server is used, or, if the site
		is started from a snapshot, the server the snapshot was taken
		from, which is the only one it can be restored into.

	-B <file>
	--blueprint=<file>
		Builds the site that the blueprint <file> describes, instead
		of the one a configuration file names, if any. See BLUEPRINT
		below.

	--no-blueprint
		Builds the site without a blueprint, even if a configuration
		file names one. Can't be given together with -B or
		--blueprint.

	--destroy
		Destroys the site [NAME]: deletes the DDEV project, including
		its database, and removes the site directory from the file
		system. Asks for confirmation before doing so. All other
		options are ignored.

	-c <file>
	--config=<file>
		Reads personal settings, and the blueprint to use, from the
		configuration file <file>, or from standard input if <file>
		is -. See CONFIGURATION below.

	-h
	--help
		Display this help and exit.

CONFIGURATION
	mkwp reads the configuration file given with -c or --config, if
	any, and the configuration file ~/.mkwp. If ~/.mkwp is missing, an
	empty one is created.

	A configuration file holds your personal settings, and may name a
	blueprint. Each line is a key, an equal sign and a value, with
	optional white space around the equal sign. Blank lines and lines
	starting with # are ignored. Any other line stops mkwp. Example:

		# Personal settings
		email = jane@example.com
		user = jane
		directory = /Users/jane/Sites
		blueprint = ~/blueprints/default.json

	The keys are:

	email
	user
	password
	directory
		The same as the options with the same names.

	blueprint
		The blueprint to build the site from when none is given with
		-B or --blueprint. A path starting with ~/ is in your home
		directory, and a relative path is relative to the directory of
		the configuration file, or to the current directory if the
		configuration is read from standard input. A blueprint named
		in the file given with -c is used instead of one named in
		~/.mkwp. Give --no-blueprint to build a site without it.

	Before mkwp 2.0.0, a configuration file could also hold the site
	settings name, dirname, title, language, themes, plugins,
	mu-plugins, php, wp and redis. Now they stop mkwp. Give name
	and dirname on the command line, and the others in a blueprint
	or as options.

BLUEPRINT
	A blueprint is a JSON file that describes a site. Keep it, and the
	files it refers to, in a directory of their own, which can be a Git
	repository and cloned anywhere. mkwp checks the whole blueprint, and
	every file it refers to, before it makes anything. Example:

		{
		  "$schema": "https://raw.githubusercontent.com/Kntnt/mkwp/main/blueprint.schema.json",
		  "note": "Our starting point for client sites",
		  "site": { "title": "Client Site", "language": "sv_SE", "php": "8.4", "redis": true },
		  "themes": [
		    "twentytwentyfive",
		    { "source": "./themes/client-child", "activate": true }
		  ],
		  "plugins": [
		    { "source": "query-monitor", "version": "3.19.0", "activate": true },
		    { "source": "git@github.com:example/private-plugin.git", "ref": "v2.1.0", "activate": true },
		    { "source": "./plugins/commercial-plugin.zip", "note": "Licensed to us" }
		  ],
		  "mu_plugins": [
		    "./mu-plugins/client-tweaks.php",
		    "https://raw.githubusercontent.com/Kntnt/kntnt-adminbar-sanitizer/master/kntnt-adminbar-sanitizer.php"
		  ]
		}

	A blueprint is an object with these keys, all of them optional:

	$schema
		The JSON Schema of the blueprint, which lets an editor check
		and complete it. mkwp ignores it.

	note
		A note of your own, since JSON has no comments. It may also be
		given in each item of themes, plugins, mu_plugins and
		files. mkwp ignores it.

	site
		An object with the settings of the site: title, language, php,
		wp and db_server, which are strings, and redis, which is true
		or false. Each is checked like the option with the same name,
		and is replaced by the option when it's given on the command
		line.

	themes
	plugins
		Arrays of the themes and plugins to install. An item is a
		source, as described below, or an object with the source in
		source, and with version, ref, activate (true or false) and
		note. version is the version to install, and only a slug on
		WordPress.org may have it. ref is the tag, branch or commit to
		check out, and only a Git repository may have it. Neither may
		hold white space or start with a hyphen, which Git would take
		for an option. Each item with "activate": true is activated,
		and at most one theme may have it. If no theme has it, the
		last theme is activated, unless there is a database. Themes
		and plugins given with -T and -P are installed after the
		blueprint's, and the last theme given with -T is activated
		instead of the blueprint's.

	mu_plugins
		An array of the mu-plugins to install. An item is a source, as
		described below, or an object with the source in source, and
		with note.

	files
		An array of the files and directories to copy into wp-content,
		such as the media that a database refers to. An item is an
		object with a local file or directory in source, where to
		copy it in target, and note. A relative source is relative
		to the blueprint's directory. The target is relative to
		wp-content. It must not be absolute or start with ~, and its ..
		parts must not lead out of wp-content. Missing directories in
		it are created.

		As with cp, the target of a file is the path of the copy, so
		the copy can get a new name, as in "uploads/2024/01/logo.png",
		and replaces a file with the same path. A target that ends
		with /, or is a directory that already exists, is the
		directory to copy the file into under its own name. The
		target of a directory is the directory to merge its contents
		into. Example:

			"files": [
			  { "source": "./media", "target": "uploads" },
			  { "source": "./fonts/brand.woff2", "target": "fonts/" },
			  { "source": "./logo.png", "target": "uploads/2024/01/client-logo.png" }
			]

	database
		The path to a database to start the site from: a dump of
		another WordPress site or a DDEV snapshot of one. Its tables
		must have the prefix wp_. A relative path is relative to the
		blueprint's directory.

		mkwp tells a dump from a snapshot by its name. A dump is plain
		SQL in a .sql file or gzip-compressed SQL in a .sql.gz file. A
		snapshot is a file that ddev snapshot made, in any directory,
		with the name DDEV gave it, which ends with the server it was
		taken from, as in site-mariadb_11.8.zst. The site gets that
		server, since a snapshot can only be restored into it, so a
		db_server in site, or one given with --db-server, must be the
		same.

		The site keeps the users, settings and active theme and
		plugins of the database, but for what is given explicitly:
		the themes and plugins with "activate": true and the theme
		given with -T are activated, and a title and a language given
		replace those of the database. Without a language given, the
		language pack of the database's language is installed, so
		that the site shows in it. What mkwp gives a new site by
		default, such as a title made from NAME, pretty permalinks
		and the timezone of the language, is not applied. The user
		is made an administrator with the email address and
		password given, and is created if the database doesn't have
		it. If the email address belongs to another user in the
		database, mkwp stops, since WordPress can't give two users
		the same email address. A dump or a snapshot can hold
		secrets, such as licence keys and API credentials, which
		mkwp doesn't remove.

		Before mkwp 2.1.0, database was an object with the path in
		dump or snapshot, and the server in server. It still works,
		with a warning, but mkwp 3.0.0 won't accept it. Give the path
		as database instead, and the server as db_server in site.

	wp_cli
		An array of WP-CLI commands, which are run in the given order at
		the end of the build. A command is an array of the arguments to
		wp, without wp itself, such as
		["option", "update", "blogdescription", "Just another site"].
		Each argument reaches WP-CLI exactly as written, since no shell
		is involved, so nothing needs quoting. A command gets no input,
		so give --yes to a command that asks for confirmation. If a
		command fails, mkwp stops without opening the site.

	The source of a theme or plugin is one of these, recognized in this
	order:

		A local path, which starts with ./, ../, / or ~/, to a
		directory or a zip file. A relative path is relative to the
		blueprint's directory. A directory is copied into the site
		under its own name. A zip file is installed, and the theme or
		plugin is named after the directory in the zip file, so the
		file's own name doesn't matter.

		A Git repository, whose URL ends with .git. Any URL that Git
		accepts works, including SSH, so a private repository is
		reached with your own SSH setup. The tag, branch or commit in
		ref is checked out, or else the latest tag, or the default
		branch if there is no tag.

		A URL, which starts with http:// or https://, to a zip file,
		which is named after the directory in it, as a local one is.

		A slug on WordPress.org, which is anything else. The version
		in version is installed, or else the latest one. A slug has
		only lower-case letters, digits, - and _, so a local path
		written without ./ in front is reported before anything is
		made.

	The source of an mu-plugin is a PHP file, given by a local path,
	which starts with ./, ../, / or ~/ and is relative to the
	blueprint's directory if it's relative, or by a URL, which starts
	with http:// or https://.

	A site is built in this order:

		- DDEV is configured, with the cron add-on and, if Redis is
		  used, the Redis add-on, and started.
		- WordPress is downloaded and installed.
		- The themes, plugins and mu-plugins are installed.
		- The files are copied into wp-content.
		- The dump is imported, or the snapshot restored, if there
		  is one. The old address is replaced by the site's, also
		  where it's JSON-escaped, the database is upgraded, the
		  user is made an administrator, the title and language
		  given are applied, or else the language pack of the
		  database's language is installed, and the rewrite rules
		  and the object cache are flushed.
		- The theme to activate, and the plugins with
		  "activate": true, are activated.
		- Redis is enabled as object cache, if it is used.
		- The WP-CLI commands in wp_cli are run, in order.
		- The site is opened in the browser.

DEPENDENCY
	This command requires that a Docker provider is installed and running
	on your system and that DDEV is properly installed and in your path.
	A blueprint also requires jq.

Blueprints

A blueprint is a JSON file that describes a site, and mkwp --blueprint=<file> NAME builds that site. The format, the rules for sources and the order in which a site is built are described under BLUEPRINT in the usage above, which also has an example.

A relative path in a blueprint is relative to the blueprint's own directory, so a blueprint and the zip files, directories, PHP files and other files it refers to can be kept together in a directory of their own. That directory can be a Git repository, private if it holds commercial plugins or code of your own, and can be cloned anywhere.

To build every site from a blueprint of yours unless you say otherwise, name it in ~/.mkwp, as in blueprint = ~/blueprints/default.json. A blueprint named in a configuration file given with -c, such as one for a client, is used instead, and a blueprint given with --blueprint is used before either. --no-blueprint builds a plain site. The configuration files hold only your personal settings and that blueprint; everything that describes the site belongs in the blueprint. See CONFIGURATION in the usage above.

A blueprint's database is the path to a dump or a DDEV snapshot of another site, as in "database": "./site.sql.gz", and starts the site with all the settings and content that site has. Only a database whose tables have the prefix wp_ can be used. A snapshot is a file that ddev snapshot writes into a site's .ddev/db_snapshots. Copy it next to the blueprint, or anywhere else, but keep the name DDEV gave it: mkwp tells a snapshot from a dump by its name, and DDEV reads the server the snapshot was taken from in it, as in site-mariadb_11.8.zst, and restores it only into that server. mkwp gives the site that server, so a blueprint needs no server for a snapshot, and a db_server in its site, or a server given with --db-server, must be the same.

A dump or a snapshot can contain secrets. Plugins keep licence keys, API credentials and similar secrets in the database, and a dump or a snapshot holds them as they are. A snapshot holds even more: every database on the server it was taken from. mkwp copies a dump or a snapshot into the new site without sanitizing it. Keep dumps and snapshots only where those secrets may be, such as a private repository, and remove what doesn't belong there before you add one to a blueprint.

blueprint.schema.json in this repository is a JSON Schema for blueprints. Name it in a blueprint's $schema key, as the example does, and an editor such as VS Code checks the blueprint and completes its keys as you write. The schema on main follows the latest mkwp. For the schema of a particular version, put its tag in place of main, as in https://raw.githubusercontent.com/Kntnt/mkwp/v2.0.0/blueprint.schema.json.

Testing

mkwp has two test suites. Both run mkwp the way a user does and look only at what a user sees: the exit status, the message, and the site that was built. Neither reads or changes your ~/.mkwp.

The fast suite checks that mkwp rejects what it must reject before it touches DDEV. It needs neither Docker nor DDEV, and takes a few seconds:

tests/run-fast

The end-to-end suite builds real sites and checks them through ddev wp. It needs a running Docker provider, DDEV on your PATH and access to the internet, and takes a few minutes. Run it before a release:

tests/run-e2e

Each site it builds is named mkwp-e2e- followed by a random part, is created in a temporary directory, and is destroyed with mkwp --destroy when its test file is done, even if a test fails or you interrupt the run. It touches no other DDEV project.

To run only some of the tests, name their files, as in tests/run-fast tests/fast/options.bash. A test is a function whose name starts with test_, in a file under tests/fast or tests/e2e. The helpers the tests use are in tests/lib.

Releasing

/release tags the release, and bin/build-release-assets builds the mkwp it attaches: the script as committed at the tag, with the tag's version written into it. The repository keeps no version number anywhere else; the tag and CHANGELOG.md carry it.

About

Bash script to quickly and easily create local WordPress sites.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages