2016-11-24 12:54:43 +01:00
wp-cli-fixtures
2016-11-24 12:52:34 +01:00
=========================
2021-02-24 17:19:37 +01:00
[](https://github.com/nlemoine/wp-cli-fixtures/actions/workflows/testing.yml?query=branch%3Amaster+workflow%3ATesting)
2021-02-24 17:15:47 +01:00


2016-11-24 13:14:25 +01:00
2016-11-24 12:52:34 +01:00
Inspired by [Faker ](https://github.com/trendwerk/faker ), this package provides an easy way to create massive and custom fake data for your WordPress installation.
2016-11-24 16:33:36 +01:00
This package is based on [nelmio/alice ](https://github.com/nelmio/alice ) and [fzaninotto/Faker ](https://github.com/fzaninotto/Faker ). Please refer to these packages docs for advanced usage.
2020-05-03 11:48:27 +02:00

2016-11-25 19:13:19 +01:00
2016-11-25 17:22:04 +01:00
**WARNING:** This package is mostly intented to be used for development purposes. Use it at your own risk, don't run it on a production database or make sure to back it up first.
2016-11-24 12:52:34 +01:00
2018-02-07 16:03:48 +01:00
Quick links: [Install ](#install ) | [Usage ](#usage ) | [Contribute ](#contribute )
2016-11-24 12:52:34 +01:00
## Install
2016-12-08 18:32:20 +01:00
```bash
2018-02-07 16:03:48 +01:00
wp package install git@github .com:nlemoine/wp-cli-fixtures.git
2016-11-24 12:52:34 +01:00
```
2016-11-25 17:37:36 +01:00
2021-02-24 17:08:16 +01:00
Requires PHP `^7.3` .
2016-11-24 12:52:34 +01:00
## Usage
### Create fixtures
2016-12-09 18:09:19 +01:00
At the root of your project, create a `fixtures.yml` file (you can download it [here ](https://raw.githubusercontent.com/nlemoine/wp-cli-fixtures/master/examples/fixtures.yml )):
2016-11-24 12:52:34 +01:00
2016-11-24 12:53:24 +01:00
```yaml
2019-04-06 12:19:54 +02:00
#
# USERS
#
2016-11-24 12:52:34 +01:00
Hellonico\Fixtures\Entity\User:
user{1..10}:
2016-11-25 17:22:04 +01:00
user_login (unique): < username ( ) > # '(unique)' is required
2019-04-06 12:19:54 +02:00
user_pass: 123456
user_email: < safeEmail ( ) >
user_url: < url ( ) >
user_registered: < dateTimeThisDecade ( ) >
first_name: < firstName ( ) >
last_name: < lastName ( ) >
description: < sentence ( ) >
role: < randomElement ( [ ' subscriber ' , ' editor ' ] ) >
2016-11-24 12:52:34 +01:00
meta:
2019-04-06 12:19:54 +02:00
phone_number: < phoneNumber ( ) >
address: < streetAddress ( ) >
zip: < postcode ( ) >
city: < city ( ) >
acf:
2019-04-18 11:31:01 +02:00
facebook_url: < url ( ) >
twitter_url: < url ( ) >
2019-04-06 12:19:54 +02:00
#
# ATTACHMENTS
#
2016-11-24 12:52:34 +01:00
Hellonico\Fixtures\Entity\Attachment:
2019-04-06 12:19:54 +02:00
default (template): # templates can be extended to keep things DRY
post_title: < words ( 2 , true ) >
post_date: < dateTimeThisDecade ( ) >
post_content: < paragraphs ( 5 , true ) >
images{1..15} (extends default):
2021-03-09 14:56:57 +01:00
file: < image ( < uploadDir ( ) > , 1200, 1200, 'cats')> # < uploadDir ( ) > is required, image() is the default faker provider and gets images from lorempixel.
pics{1..15} (extends default):
file: < picsum ( < uploadDir ( ) > , 1200, 1200)> # Alternatively we provide a picsum() provider which uses picsum for images. It's quicker but doesn't support image categories.
2019-04-06 12:19:54 +02:00
documents{1..2} (extends default):
file: < fileIn ( ' relative / path / to / pdfs ' ) >
custom_images{1..10} (extends default):
file: < fileIn ( ' relative / path / to / images ' ) >
#
# TERMS
#
2016-11-24 12:52:34 +01:00
Hellonico\Fixtures\Entity\Term:
category{1..10}:
2019-04-06 12:19:54 +02:00
name (unique): < words ( 2 , true ) > # '(unique)' is required
description: < sentence ( ) >
2016-12-09 11:55:40 +01:00
parent: '50%? < termId ( childless = 1) > ' # 50% of created categories will have a top level parent category
2016-11-25 17:22:04 +01:00
taxonomy: 'category' # could be skipped, default to 'category'
tag{1..40}:
2019-04-06 12:19:54 +02:00
name (unique): < words ( 2 , true ) > # '(unique)' is required
description: < sentence ( ) >
taxonomy: post_tag
places{1..4}: # custom taxonomy
name (unique): < words ( 2 , true ) > # '(unique)' is required
description: < sentences ( 3 , true ) >
taxonomy: place
acf:
address: < streetAddress >
2019-04-18 11:31:01 +02:00
zip: < postcode ( ) >
city: < city ( ) >
2019-04-06 12:19:54 +02:00
image: '@custom_images *->ID'
#
# POSTS
#
2016-11-24 12:52:34 +01:00
Hellonico\Fixtures\Entity\Post:
2019-04-06 12:19:54 +02:00
# TEMPLATE
default (template):
post_title: < words ( 2 , true ) >
post_date: < dateTimeThisDecade ( ) >
post_content: < paragraphs ( 5 , true ) >
post_excerpt: < paragraphs ( 1 , true ) >
meta:
_thumbnail_id: '@attachment *->ID'
# POSTS
post{1..30} (extends default):
2016-12-01 16:57:40 +01:00
# 'meta' and 'meta_input' are basically the same, you can use one or both,
2016-11-24 17:30:40 +01:00
# they will be merged, just don't provide the same keys in each definition
2016-11-24 12:52:34 +01:00
meta:
2019-04-06 12:19:54 +02:00
_thumbnail_id: '@attachment *->ID'
2016-11-24 12:52:34 +01:00
meta_input:
2019-04-06 12:19:54 +02:00
_extra_field: < paragraphs ( 1 , true ) >
2016-11-24 17:28:42 +01:00
post_category: '3x @category *->term_id' # post_category only accepts IDs
tax_input:
2016-11-28 13:35:07 +01:00
post_tag: '5x @tag *->term_id'
2019-04-06 12:19:54 +02:00
# post_tag: '5x < words ( 2 , true ) > # Or tags can be dynamically created
# PAGES
page{contact, privacy}:
post_title: < current ( ) >
post_type: page
2016-12-01 16:57:40 +01:00
2019-04-06 12:19:54 +02:00
# CUSTOM POST TYPE
product{1..15}:
post_type: product
acf:
2019-04-18 11:31:01 +02:00
# number field
2019-04-06 12:19:54 +02:00
price: < numberBetween ( 10 , 200 ) >
2019-04-18 11:31:01 +02:00
# gallery field
gallery: '3x @attachment *->ID'
# oembed field
video: https://www.youtube.com/watch?v=E90_aL870ao
# link field
link:
url: https://www.youtube.com/watch?v=E90_aL870ao
title: < words ( 2 , true ) >
target: _blank
# repeater field
features:
2019-04-06 12:19:54 +02:00
- label: < words ( 2 , true ) >
2022-12-13 20:01:34 +01:00
value: < sentence ( ) >
2019-04-06 12:19:54 +02:00
- label: < words ( 2 , true ) >
value: < sentence ( ) >
- label: < words ( 2 , true ) >
value: < sentence ( ) >
2019-04-18 11:31:01 +02:00
# layout field
blocks:
- acf_fc_layout: text_image
title: < words ( 4 , true ) >
content: < sentences ( 8 , true ) >
image: '@attachment *->ID'
- acf_fc_layout: image_image
image_left: '@attachment *->ID'
image_right: '@attachment *->ID'
2019-04-06 12:19:54 +02:00
#
# COMMENTS
#
2016-11-24 12:52:34 +01:00
Hellonico\Fixtures\Entity\Comment:
comment{1..50}:
comment_post_ID: '@post *->ID'
user_id: '@user *->ID'
2019-04-06 12:19:54 +02:00
comment_date: < dateTimeThisDecade ( ) >
comment_author: < username ( ) >
comment_author_email: < safeEmail ( ) >
comment_author_url: < url ( ) >
comment_content: < paragraphs ( 2 , true ) >
comment_agent: < userAgent ( ) >
comment_author_IP: < ipv4 ( ) >
2016-12-08 18:27:30 +01:00
comment_approved: 1
2019-04-06 12:19:54 +02:00
comment_karma: < numberBetween ( 1 , 100 ) >
2016-12-01 16:57:40 +01:00
# 'meta' and 'comment_meta' are basically the same, you can use one or both,
# they will be merged, just don't provide the same keys in each definition
comment_meta:
2019-04-06 12:19:54 +02:00
some_key: < sentence ( ) >
2016-12-01 16:57:40 +01:00
meta:
2019-04-06 12:19:54 +02:00
another_key: < sentence ( ) >
2019-04-18 11:31:01 +02:00
2021-03-09 14:56:57 +01:00
#
# NAV MENUS
#
Hellonico\Fixtures\Entity\NavMenu:
header:
name: header
locations:
- header
- footer
#
# NAV MENUS ITEMS
#
Hellonico\Fixtures\Entity\NavMenuItem:
custom_menu:
menu_item_url: < url ( ) >
menu_item_title: < words ( 4 , true ) >
menu_id: '@header ->term_id'
categories{1..3}:
menu_item_object: '@category *'
menu_id: '@header ->term_id'
posts{1..3}:
menu_item_object: '@post *'
menu_id: '@header ->term_id'
page:
menu_item_object: '@page *'
menu_id: '@header ->term_id'
2016-11-24 12:52:34 +01:00
```
2016-11-24 16:33:36 +01:00
The example above will generate:
- 10 users
- 15 attachments
2016-11-25 17:22:04 +01:00
- 10 categories
- 40 tags
2016-11-24 17:28:42 +01:00
- 30 posts with a thumbnail, 3 categories and 5 tags
2018-02-07 16:03:48 +01:00
- 10 pages
- 15 custom post types named 'product'
2016-11-24 18:16:44 +01:00
- 50 comments associated with post and user
2021-03-09 14:56:57 +01:00
- 1 nav menu
- 6 nav menu items
2016-11-24 12:52:34 +01:00
2016-11-24 16:33:36 +01:00
**IMPORTANT:** Make sure referenced IDs are placed **BEFORE** they are used.
2019-04-06 12:19:54 +02:00
Example: `Term` or `Attachment` objects **must** be placed before `Post` if you're referencing them in your fixtures.
2016-11-24 18:13:12 +01:00
2016-11-24 12:52:34 +01:00
### Load fixtures
```
wp fixtures load
```
You can also specify a custom file by using the `--file` argument:
```
wp fixtures load --file=data.yml
```
### Delete fixtures
```
wp fixtures delete
```
2016-11-24 16:33:36 +01:00
You also can delete a single fixture type:
2016-11-24 12:52:34 +01:00
```
wp fixtures delete post
```
Valid types are `post` , `attachment` , `comment` , `term` , `user` .
2016-11-24 18:13:12 +01:00
### Add fake data to existing content
2016-12-01 16:57:40 +01:00
`wp-cli-fixtures` allows you to add/update content to existing entities by passing the ID as a constructor argument.
2016-11-24 18:13:12 +01:00
2016-11-25 17:22:04 +01:00
Add/update data to post ID 1:
2016-11-24 18:13:12 +01:00
```yaml
Hellonico\Fixtures\Entity\Post:
my_post:
__construct: [1] # Pass your post ID as the constructor argument
post_title: '< sentence ( ) > '
post_content: '< paragraphs ( 5 , true ) > '
post_excerpt: '< paragraphs ( 1 , true ) > '
```
2016-11-25 17:22:04 +01:00
Add/update data to 10 random existing posts:
2016-11-24 18:13:12 +01:00
```yaml
Hellonico\Fixtures\Entity\Post:
2016-11-25 17:22:04 +01:00
post{1..10}:
__construct: [< postId ( ) > ] # Use a custom formatters to return a random post ID as the constructor argument
2016-11-24 18:13:12 +01:00
post_title: '< sentence ( ) > '
post_content: '< paragraphs ( 5 , true ) > '
post_excerpt: '< paragraphs ( 1 , true ) > '
```
2018-02-07 16:03:48 +01:00
### Entities
#### Post
2019-04-06 12:19:54 +02:00
`Hellonico\Fixtures\Entity\Post` can take any parameters available in [`wp_insert_post` ](https://developer.wordpress.org/reference/functions/wp_insert_post/#parameters ) + `meta` and `acf` key.
2018-02-07 16:03:48 +01:00
2019-04-06 12:19:54 +02:00
*Note: `post_date_gmt` and `post_modified_gmt` have been disabled, there are set from `post_date` and `post_modified` .*
2018-02-07 16:03:48 +01:00
#### Attachment
2019-04-06 12:19:54 +02:00
`Hellonico\Fixtures\Entity\Attachment` can take any parameters available in [`wp_insert_attachment` ](https://developer.wordpress.org/reference/functions/wp_insert_attachment/#parameters ) + `meta` , `file` and `acf` custom keys.
*Note: `parent` must be passed with `post_parent` key.*
2018-02-07 16:03:48 +01:00
#### Term
2019-04-06 12:19:54 +02:00
`Hellonico\Fixtures\Entity\Term` can take any parameters available in [`wp_insert_term` ](https://developer.wordpress.org/reference/functions/wp_insert_term/#parameters ) + `meta` and `acf` custom keys.
*Note: `term` and `taxonomy` must be respectively passed with `name` and `taxonomy` key.*
2018-02-07 16:03:48 +01:00
#### User
2019-04-06 12:19:54 +02:00
`Hellonico\Fixtures\Entity\User` can take any parameters available in [`wp_insert_user` ](https://developer.wordpress.org/reference/functions/wp_insert_user/#parameters ) + `meta` and `acf` custom keys.
2018-02-07 16:03:48 +01:00
#### Comment
`Hellonico\Fixtures\Entity\Comment` can take any parameters available in [`wp_insert_comment` ](https://developer.wordpress.org/reference/functions/wp_insert_comment/#parameters ) + `meta` custom key.
`comment_date_gmt` has been disabled, it is set from `comment_date` .
2016-11-24 18:13:12 +01:00
2021-03-09 14:56:57 +01:00
#### Nav menu
`Hellonico\Fixtures\Entity\NavMenu` is a term just like `Hellonico\Fixtures\Entity\Term` . It takes an addiotional `locations` parameter to set the menu location.
```yaml
Hellonico\Fixtures\Entity\NavMenu:
header:
name: header
locations:
- header
```
#### Nav menu item
`Hellonico\Fixtures\Entity\NavMenuItem` takes the same parameters as `$menu_item_data` in [`wp_update_nav_menu_item` ](https://developer.wordpress.org/reference/functions/wp_update_nav_menu_item/#parameters )
*Note 1: replace dashes with underscore in keys (e.g. `menu-item-object` becomes `menu_item_object` ).*
*Note 2: `menu-item-object` can also accept an entity object, if so, `menu-item-type` and `menu-item-object-id` will be filled automatically with appropriate values*
2019-04-06 12:19:54 +02:00
### ACF Support
Each ACF supported entity (post, term, user) can have an `acf` key, which works just like `meta` .
```yaml
Hellonico\Fixtures\Entity\Post:
post{1..30}:
post_title: < words ( 3 , true ) >
post_date: < dateTimeThisDecade ( ) >
acf:
# number field
number: < numberBetween ( 10 , 200 ) >
# repeater field
features:
- label: < words ( 2 , true ) >
2024-11-14 22:07:20 +01:00
value: < sentence ( ) >
2019-04-06 12:19:54 +02:00
- label: < words ( 2 , true ) >
value: < sentence ( ) >
- label: < words ( 2 , true ) >
value: < sentence ( ) >
```
Be careful with duplicate field keys, if you have multiple field with the same key, prefer using ACF field key (`field_948d1qj5mn4d3` ).
2024-11-14 22:07:20 +01:00
### MetaBox Support
#### MetaBox Custom Fields
MetaBox fields can be adressed using the `meta` key
```yaml
Hellonico\Fixtures\Entity\Post:
post{1..30}:
post_title: < words ( 3 , true ) >
post_date: < dateTimeThisDecade ( ) >
meta:
# number field
number: < numberBetween ( 10 , 200 ) >
meta_box_custom_field: < sentence ( ) >
```
#### MetaBox Relationships (https://docs.metabox.io/extensions/mb-relationships/#using-code)
When using the MB Relationships extension, the relationships can be set/defined using the key `mb_relations` . For each relationship you want to create a fixture for, you use the relationship-ID which is used to register the MB-relation
```php
MB_Relationships_API::register( [
'id' => 'post_to_term',
'from' => 'post',
'to' => [
'object_type' => 'term',
'taxonomy'=> 'custom_term'
],
] );
```
and the post/term ID of the object you want it to have a relationship with.
```yaml
Hellonico\Fixtures\Entity\Post:
post{1..30}:
post_title: < words ( 3 , true ) >
post_date: < dateTimeThisDecade ( ) >
mb_relations:
post_to_term: '1x @custom_term *->term_id'
post_to_post: '1x @custom_post *->ID'
```
2016-11-24 16:33:36 +01:00
### Custom formatters
2016-11-24 18:13:12 +01:00
In addition to formatters provided by [fzaninotto/Faker ](https://github.com/fzaninotto/Faker#formatters ), you can use custom formatters below.
2016-11-24 16:33:36 +01:00
#### `postId($args)`
2016-12-01 16:57:40 +01:00
Returns a random existing post ID.
2016-11-24 18:13:12 +01:00
`$args` is optional and can take any arguments from [`get_posts` ](https://developer.wordpress.org/reference/functions/get_posts/#parameters )
2016-11-24 16:33:36 +01:00
Example:
```
< postId ( category = 1,2,3) >
```
#### `attachmentId($args)`
2016-12-01 16:57:40 +01:00
Returns a random existing attachment ID.
2016-11-24 18:13:12 +01:00
`$args` is optional and can take any arguments from [`get_posts` ](https://developer.wordpress.org/reference/functions/get_posts/#parameters )
2016-11-24 16:33:36 +01:00
Example:
```
< attachmentId ( year = 2016) >
```
#### `termId($args)`
2016-12-01 16:57:40 +01:00
Returns a random existing term ID.
2016-11-24 18:13:12 +01:00
`$args` is optional and can take any arguments from [`get_terms` ](https://developer.wordpress.org/reference/functions/get_terms/#parameters )
2016-11-24 16:33:36 +01:00
Example:
```
< termId ( taxonomy = post_tag) >
```
#### `userId($args)`
2016-12-01 16:57:40 +01:00
Returns a random existing user ID.
2016-11-24 18:13:12 +01:00
`$args` is optional and can take any arguments from [`get_users` ](https://developer.wordpress.org/reference/functions/get_users/#parameters )
2016-11-24 16:33:36 +01:00
Example:
```
< userId ( role = subscriber) >
```
2019-04-06 12:19:54 +02:00
#### `fileContent($file)`
Returns the content of a file.
Example:
```
< fileContent ( ' path / to / file . html ' ) >
```
#### `fileIn($src, $target, false)`
Wrapper around [file provider ](https://github.com/fzaninotto/Faker#fakerproviderfile ) because some Faker providers [conflicts with PHP native ](https://github.com/nelmio/alice/blob/master/doc/getting-started.md#symfony ). Returns file path or file name in a directory (`$src` relative to `fixtures.yml` ).
Default target is the WordPress `uploads` .
Example:
```
< fileIn ( ' my / set / of / images ' ) >
```
2018-02-07 16:03:48 +01:00
#### Tips
While playing with fixtures, the [database command ](https://github.com/ernilambar/database-command ) package can be useful to reset database faster than `wp fixtures delete` and start over.
2016-11-24 12:52:34 +01:00
2018-02-07 16:03:48 +01:00
## Contribute
2016-11-24 12:52:34 +01:00
2021-02-24 17:08:16 +01:00
This package follows PSR2 coding standards and is tested with Behat. Execute `composer run test` to ensure your PR passes.
2018-02-07 18:52:29 +01:00
2020-05-03 11:48:27 +02:00
> You will need to run `composer run prepare-tests` before your first run.