Skip to content

Commit df75074

Browse files
committed
Merge branch 'main' into copilot/add-stdin-support-to-media-import
2 parents 560ac7a + d2edbef commit df75074

9 files changed

Lines changed: 967 additions & 184 deletions

.gitattributes

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/.actrc export-ignore
2+
/.distignore export-ignore
3+
/.editorconfig export-ignore
4+
/.github export-ignore
5+
/.gitignore export-ignore
6+
/.typos.toml export-ignore
7+
/AGENTS.md export-ignore
8+
/behat.yml export-ignore
9+
/features export-ignore
10+
/phpcs.xml.dist export-ignore
11+
/phpstan.neon.dist export-ignore
12+
/phpunit.xml.dist export-ignore
13+
/tests export-ignore
14+
/wp-cli.yml export-ignore

.github/workflows/copilot-setup-steps.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,11 @@ jobs:
2121

2222
- name: Check existence of composer.json file
2323
id: check_composer_file
24-
uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3
25-
with:
26-
files: "composer.json"
24+
run: echo "files_exists=$(test -f composer.json && echo true || echo false)" >> "$GITHUB_OUTPUT"
2725

2826
- name: Set up PHP environment
2927
if: steps.check_composer_file.outputs.files_exists == 'true'
30-
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2
28+
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
3129
with:
3230
php-version: 'latest'
3331
ini-values: zend.assertions=1, error_reporting=-1, display_errors=On
@@ -38,7 +36,7 @@ jobs:
3836

3937
- name: Install Composer dependencies & cache dependencies
4038
if: steps.check_composer_file.outputs.files_exists == 'true'
41-
uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3
39+
uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # v3
4240
env:
4341
COMPOSER_ROOT_VERSION: dev-${{ github.event.repository.default_branch }}
4442
with:

README.md

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,49 @@ wp media
5454

5555

5656

57+
### wp media fix-orientation
58+
59+
Fix image orientation for one or more attachments.
60+
61+
~~~
62+
wp media fix-orientation [<attachment-id>...] [--dry-run]
63+
~~~
64+
65+
**OPTIONS**
66+
67+
[<attachment-id>...]
68+
One or more IDs of the attachments to regenerate.
69+
70+
[--dry-run]
71+
Check images needing orientation without performing the operation.
72+
73+
**EXAMPLES**
74+
75+
# Fix orientation for all images.
76+
$ wp media fix-orientation
77+
1/3 Fixing orientation for "Landscape_4" (ID 62).
78+
2/3 Fixing orientation for "Landscape_3" (ID 61).
79+
3/3 Fixing orientation for "Landscape_2" (ID 60).
80+
Success: Fixed 3 of 3 images.
81+
82+
# Fix orientation dry run.
83+
$ wp media fix-orientation 63 --dry-run
84+
1/1 "Portrait_6" (ID 63) will be affected.
85+
Success: 1 of 1 image will be affected.
86+
87+
# Fix orientation for specific images.
88+
$ wp media fix-orientation 63
89+
1/1 Fixing orientation for "Portrait_6" (ID 63).
90+
Success: Fixed 1 of 1 images.
91+
92+
93+
5794
### wp media import
5895

5996
Creates attachments from local files or URLs.
6097

6198
~~~
62-
wp media import <file>... [--post_id=<post_id>] [--post_name=<post_name>] [--file_name=<name>] [--title=<title>] [--caption=<caption>] [--alt=<alt_text>] [--desc=<description>] [--skip-copy] [--preserve-filetime] [--featured_image] [--porcelain[=<field>]]
99+
wp media import <file>... [--post_id=<post_id>] [--post_name=<post_name>] [--file_name=<name>] [--title=<title>] [--caption=<caption>] [--alt=<alt_text>] [--desc=<description>] [--skip-copy] [--destination-dir=<destination-dir>] [--preserve-filetime] [--featured_image] [--porcelain[=<field>]]
63100
~~~
64101

65102
**OPTIONS**
@@ -92,7 +129,13 @@ wp media import <file>... [--post_id=<post_id>] [--post_name=<post_name>] [--fil
92129

93130
[--skip-copy]
94131
If set, media files (local only) are imported to the library but not moved on disk.
95-
File names will not be run through wp_unique_filename() with this set.
132+
File names will not be run through wp_unique_filename() with this set. When used, files
133+
will remain at their current location and will not be copied into any destination directory.
134+
135+
[--destination-dir=<destination-dir>]
136+
Path to the destination directory for uploaded imported files.
137+
Can be absolute or relative to ABSPATH. Ignored when used together with --skip-copy, as
138+
files are not moved on disk in that case.
96139

97140
[--preserve-filetime]
98141
Use the file modified time as the post published & modified dates.
@@ -145,16 +188,16 @@ wp media import <file>... [--post_id=<post_id>] [--post_name=<post_name>] [--fil
145188
Regenerates thumbnails for one or more attachments.
146189

147190
~~~
148-
wp media regenerate [<attachment-id>...] [--image_size=<image_size>] [--skip-delete] [--only-missing] [--delete-unknown] [--yes]
191+
wp media regenerate [<attachment-id>...] [--image_size=<image_size>...] [--skip-delete] [--only-missing] [--delete-unknown] [--yes]
149192
~~~
150193

151194
**OPTIONS**
152195

153196
[<attachment-id>...]
154197
One or more IDs of the attachments to regenerate.
155198

156-
[--image_size=<image_size>]
157-
Name of the image size to regenerate. Only thumbnails of this image size will be regenerated, thumbnails of other image sizes will not.
199+
[--image_size=<image_size>...]
200+
Name of the image size to regenerate. Repeat the flag to specify multiple. Only thumbnails of specified image size(s) will be regenerated, thumbnails of other image sizes will not.
158201

159202
[--skip-delete]
160203
Skip deletion of the original thumbnails. If your thumbnails are linked from sources outside your control, it's likely best to leave them around. Defaults to false.
@@ -204,6 +247,15 @@ wp media regenerate [<attachment-id>...] [--image_size=<image_size>] [--skip-del
204247
3/3 Regenerated "large" thumbnail for "Sunburst Over River" (ID 756).
205248
Success: Regenerated 3 of 3 images.
206249

250+
# Re-generate only the thumbnails of "large" and "medium" image sizes for all images.
251+
$ wp media regenerate --image_size=large --image_size=medium
252+
Do you really want to regenerate the "large", "medium" image sizes for all images? [y/n] y
253+
Found 3 images to regenerate.
254+
1/3 Regenerated "large", "medium" thumbnails for "Sydney Harbor Bridge" (ID 760).
255+
2/3 No "large", "medium" thumbnail regeneration needed for "Boardwalk" (ID 757).
256+
3/3 Regenerated "large", "medium" thumbnails for "Sunburst Over River" (ID 756).
257+
Success: Regenerated 3 of 3 images.
258+
207259

208260

209261
### wp media image-size

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
}
1313
],
1414
"require": {
15-
"wp-cli/wp-cli": "^2.12"
15+
"wp-cli/wp-cli": "^2.13"
1616
},
1717
"require-dev": {
1818
"wp-cli/entity-command": "^1.3 || ^2",
@@ -36,6 +36,7 @@
3636
"bundled": true,
3737
"commands": [
3838
"media",
39+
"media fix-orientation",
3940
"media import",
4041
"media regenerate",
4142
"media image-size"

features/media-fix-orientation.feature

Lines changed: 104 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ Feature: Fix WordPress attachments orientation
1111
Error: No images found.
1212
"""
1313

14-
# On WP 4.9 tests this results in "Couldn't fix orientation".
15-
# Todo: Revisit this test and improve or potentially remove it if useless.
16-
@require-extension-exif @require-wp-4.0 @less-than-wp-4.9
14+
# On WP 5.3+, images are auto-rotated by WordPress during import, so fix-orientation reports them as already fixed.
15+
@require-extension-exif @require-wp-4.0 @less-than-wp-5.3
1716
Scenario: Fix orientation for all images
1817
Given download:
1918
| path | url |
@@ -96,10 +95,8 @@ Feature: Fix WordPress attachments orientation
9695
Success: Images already fixed.
9796
"""
9897

99-
# On newer versions (5.3+) the image is already considered fixed.
100-
# On WP 4.9 tests this results in "Couldn't fix orientation".
101-
# Todo: Revisit this test and improve or potentially remove it if useless.
102-
@require-extension-exif @require-wp-4.0 @less-than-wp-4.9
98+
# On WP 5.3+, images are auto-rotated by WordPress during import, so fix-orientation reports them as already fixed.
99+
@require-extension-exif @require-wp-4.0 @less-than-wp-5.3
103100
Scenario: Fix orientation for single image
104101
Given download:
105102
| path | url |
@@ -122,10 +119,110 @@ Feature: Fix WordPress attachments orientation
122119
Success: Image already fixed.
123120
"""
124121

122+
# This specifically tests the Imagick flip-only path (orientations 2, 4) where
123+
# WP_Image_Editor_Imagick::flip() does not update the EXIF orientation tag, requiring
124+
# explicit metadata normalization after the fix.
125+
@require-extension-exif @require-extension-imagick @require-wp-4.0 @less-than-wp-5.3
126+
Scenario: Fix flip-only orientation with Imagick
127+
Given download:
128+
| path | url |
129+
| {CACHE_DIR}/landscape-2.jpg | https://raw.githubusercontent.com/thrijith/test-images/master/Landscape_2.jpg |
130+
| {CACHE_DIR}/portrait-4.jpg | https://raw.githubusercontent.com/thrijith/test-images/master/Portrait_4.jpg |
131+
And I run `wp option update uploads_use_yearmonth_folders 0`
132+
133+
When I run `wp media import {CACHE_DIR}/landscape-2.jpg --title="Landscape Two" --porcelain`
134+
Then save STDOUT as {LANDSCAPE_TWO}
135+
136+
When I run `wp media import {CACHE_DIR}/portrait-4.jpg --title="Portrait Four" --porcelain`
137+
Then save STDOUT as {PORTRAIT_FOUR}
138+
139+
When I run `wp media fix-orientation`
140+
Then STDOUT should contain:
141+
"""
142+
Fixing orientation for "Landscape Two" (ID {LANDSCAPE_TWO}).
143+
"""
144+
And STDOUT should contain:
145+
"""
146+
Fixing orientation for "Portrait Four" (ID {PORTRAIT_FOUR}).
147+
"""
148+
And STDOUT should contain:
149+
"""
150+
Success: Fixed 2 of 2 images.
151+
"""
152+
153+
# Verify that a second run reports no fix required (metadata normalized after save).
154+
When I run `wp media fix-orientation`
155+
Then STDOUT should contain:
156+
"""
157+
No orientation fix required for "Landscape Two" (ID {LANDSCAPE_TWO}).
158+
"""
159+
And STDOUT should contain:
160+
"""
161+
No orientation fix required for "Portrait Four" (ID {PORTRAIT_FOUR}).
162+
"""
163+
And STDOUT should contain:
164+
"""
165+
Success: Images already fixed.
166+
"""
167+
125168
@require-wp-4.0
126169
Scenario: Fix orientation for non existent image
127170
When I try `wp media fix-orientation 9999`
128171
Then STDERR should be:
129172
"""
130173
Error: No images found.
131174
"""
175+
176+
@require-extension-exif @require-wp-5.3
177+
Scenario: Fix orientation for all images already auto-rotated by WordPress
178+
Given download:
179+
| path | url |
180+
| {CACHE_DIR}/landscape-2.jpg | https://raw.githubusercontent.com/thrijith/test-images/master/Landscape_2.jpg |
181+
| {CACHE_DIR}/landscape-5.jpg | https://raw.githubusercontent.com/thrijith/test-images/master/Landscape_5.jpg |
182+
| {CACHE_DIR}/portrait-4.jpg | https://raw.githubusercontent.com/thrijith/test-images/master/Portrait_4.jpg |
183+
And I run `wp option update uploads_use_yearmonth_folders 0`
184+
185+
When I run `wp media import {CACHE_DIR}/landscape-2.jpg --title="Landscape Two" --porcelain`
186+
Then save STDOUT as {LANDSCAPE_TWO}
187+
188+
When I run `wp media import {CACHE_DIR}/landscape-5.jpg --title="Landscape Five" --porcelain`
189+
Then save STDOUT as {LANDSCAPE_FIVE}
190+
191+
When I run `wp media import {CACHE_DIR}/portrait-4.jpg --title="Portrait Four" --porcelain`
192+
Then save STDOUT as {PORTRAIT_FOUR}
193+
194+
When I run `wp media fix-orientation`
195+
Then STDOUT should contain:
196+
"""
197+
No orientation fix required for "Portrait Four" (ID {PORTRAIT_FOUR}).
198+
"""
199+
200+
And STDOUT should contain:
201+
"""
202+
No orientation fix required for "Landscape Five" (ID {LANDSCAPE_FIVE}).
203+
"""
204+
205+
And STDOUT should contain:
206+
"""
207+
No orientation fix required for "Landscape Two" (ID {LANDSCAPE_TWO}).
208+
"""
209+
210+
And STDOUT should contain:
211+
"""
212+
Success: Images already fixed.
213+
"""
214+
215+
@require-extension-exif @require-wp-5.3
216+
Scenario: Fix orientation for single image already auto-rotated by WordPress
217+
Given download:
218+
| path | url |
219+
| {CACHE_DIR}/portrait-6.jpg | https://raw.githubusercontent.com/thrijith/test-images/master/Portrait_6.jpg |
220+
When I run `wp media import {CACHE_DIR}/portrait-6.jpg --title="Portrait Six" --porcelain`
221+
Then save STDOUT as {PORTRAIT_SIX}
222+
223+
When I run `wp media fix-orientation {PORTRAIT_SIX}`
224+
Then STDOUT should be:
225+
"""
226+
1/1 No orientation fix required for "Portrait Six" (ID {PORTRAIT_SIX}).
227+
Success: Image already fixed.
228+
"""

features/media-import.feature

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,35 @@ Feature: Manage WordPress attachments
323323
Warning: Unable to import file from STDIN. Reason: No input provided.
324324
"""
325325
And the return code should be 1
326+
327+
Scenario: Upload files into a custom directory, relative to ABSPATH, when --destination-dir flag is applied.
328+
Given download:
329+
| path | url |
330+
| {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg |
331+
When I run `wp media import --destination-dir="foo" {CACHE_DIR}/large-image.jpg --porcelain=url`
332+
333+
Then STDOUT should not contain:
334+
"""
335+
https://example.com/wp-content/uploads/
336+
"""
337+
338+
And STDOUT should contain:
339+
"""
340+
https://example.com/foo/large-image.jpg
341+
"""
342+
343+
Scenario: Upload files into a custom directory, not relative to ABSPATH, when --destination-dir flag is applied.
344+
Given download:
345+
| path | url |
346+
| {CACHE_DIR}/large-image.jpg | http://wp-cli.org/behat-data/large-image.jpg |
347+
When I run `wp media import --destination-dir="{RUN_DIR}/foo" {CACHE_DIR}/large-image.jpg --porcelain=url`
348+
349+
Then STDOUT should not contain:
350+
"""
351+
https://example.com/wp-content/uploads/
352+
"""
353+
354+
And STDOUT should contain:
355+
"""
356+
/foo/large-image.jpg
357+
"""

0 commit comments

Comments
 (0)