Skip to content

Commit 6f55757

Browse files
authored
Merge branch 'main' into copilot/add-ranges-to-commands
2 parents f05f337 + 64a4a47 commit 6f55757

File tree

12 files changed

+255
-103
lines changed

12 files changed

+255
-103
lines changed

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ jobs:
3636

3737
- name: Install Composer dependencies & cache dependencies
3838
if: steps.check_composer_file.outputs.files_exists == 'true'
39-
uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # v3
39+
uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # v4
4040
env:
4141
COMPOSER_ROOT_VERSION: dev-${{ github.event.repository.default_branch }}
42-
with:
43-
# Bust the cache at least once a month - output format: YYYY-MM.
44-
custom-cache-suffix: $(date -u "+%Y-%m")

README.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,7 +2781,7 @@ wp post create [--post_author=<post_author>] [--post_date=<post_date>] [--post_d
27812781
[--tax_input=<tax_input>]
27822782
Array of taxonomy terms keyed by their taxonomy name. Default empty.
27832783

2784-
Note: In WordPress core, this normally requires a user context to satisfy capability checks. WP-CLI bypasses this for convenience. See https://core.trac.wordpress.org/ticket/19373
2784+
Note: In WordPress core, this normally requires a user context to satisfy capability checks. WP-CLI bypasses this for convenience. See https://core.trac.wordpress.org/ticket/19373
27852785

27862786
[--meta_input=<meta_input>]
27872787
Array in JSON format of post meta values keyed by their post meta key. Default empty.
@@ -2790,22 +2790,21 @@ wp post create [--post_author=<post_author>] [--post_date=<post_date>] [--post_d
27902790
Read post content from <file>. If this value is present, the
27912791
`--post_content` argument will be ignored.
27922792

2793-
Passing `-` as the filename will cause post content to
2794-
be read from STDIN.
2793+
Passing `-` as the filename will cause post content to
2794+
be read from STDIN.
27952795

27962796
[--<field>=<value>]
27972797
Associative args for the new post. See wp_insert_post().
27982798

27992799
[--edit]
28002800
Immediately open system's editor to write or edit post content.
28012801

2802-
If content is read from a file, from STDIN, or from the `--post_content`
2803-
argument, that text will be loaded into the editor.
2802+
If content is read from a file, from STDIN, or from the `--post_content`
2803+
argument, that text will be loaded into the editor.
28042804

28052805
[--porcelain]
28062806
Output just the new post id.
28072807

2808-
28092808
**EXAMPLES**
28102809

28112810
# Create post and schedule for future
@@ -3839,7 +3838,7 @@ wp post update <id>... [--post_author=<post_author>] [--post_date=<post_date>] [
38393838
[--tax_input=<tax_input>]
38403839
Array of taxonomy terms keyed by their taxonomy name. Default empty.
38413840

3842-
Note: In WordPress core, this normally requires a user context to satisfy capability checks. WP-CLI bypasses this for convenience. See https://core.trac.wordpress.org/ticket/19373
3841+
Note: In WordPress core, this normally requires a user context to satisfy capability checks. WP-CLI bypasses this for convenience. See https://core.trac.wordpress.org/ticket/19373
38433842

38443843
[--meta_input=<meta_input>]
38453844
Array in JSON format of post meta values keyed by their post meta key. Default empty.
@@ -3848,8 +3847,8 @@ wp post update <id>... [--post_author=<post_author>] [--post_date=<post_date>] [
38483847
Read post content from <file>. If this value is present, the
38493848
`--post_content` argument will be ignored.
38503849

3851-
Passing `-` as the filename will cause post content to
3852-
be read from STDIN.
3850+
Passing `-` as the filename will cause post content to
3851+
be read from STDIN.
38533852

38543853
--<field>=<value>
38553854
One or more fields to update. See wp_insert_post().
@@ -5218,17 +5217,18 @@ wp site delete [<site-id>] [--slug=<slug>] [--yes] [--keep-tables]
52185217

52195218
### wp site empty
52205219

5221-
Empties a site of its content (posts, comments, terms, and meta).
5220+
Empties a site of its content (posts, comments, terms, links, and meta).
52225221

52235222
~~~
52245223
wp site empty [--uploads] [--yes]
52255224
~~~
52265225

5227-
Truncates posts, comments, and terms tables to empty a site of its
5226+
Truncates posts, comments, terms, and links tables to empty a site of its
52285227
content. Doesn't affect site configuration (options) or users.
52295228

5230-
If running a persistent object cache, make sure to flush the cache
5231-
after emptying the site, as the cache values will be invalid otherwise.
5229+
Flushes the object cache after emptying the site to ensure stale data
5230+
is not served. On a Multisite installation, this will flush the cache
5231+
for all sites.
52325232

52335233
To also empty custom database tables, you'll need to hook into command
52345234
execution:
@@ -8967,6 +8967,10 @@ Want to contribute a new feature? Please first [open a new issue](https://github
89678967

89688968
Once you've decided to commit the time to seeing your pull request through, [please follow our guidelines for creating a pull request](https://make.wordpress.org/cli/handbook/pull-requests/) to make sure it's a pleasant experience. See "[Setting up](https://make.wordpress.org/cli/handbook/pull-requests/#setting-up)" for details specific to working on this package locally.
89698969

8970+
### License
8971+
8972+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
8973+
89708974
## Support
89718975

89728976
GitHub issues aren't for general support questions, but there are other venues you can try: https://wp-cli.org/#support

features/comment-recount.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Feature: Recount comments on a post
1111
3
1212
"""
1313

14-
When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->posts, array( "comment_count" => 1 ), array( "ID" => 1 ) );'`
14+
When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->posts, array( "comment_count" => 1 ), array( "ID" => 1 ) ); clean_post_cache( 1 );'`
1515
And I run `wp post get 1 --field=comment_count`
1616
Then STDOUT should be:
1717
"""

features/menu-item.feature

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ Feature: Manage WordPress menu items
103103
| Child | {CHILD_ID} | {PARENT_ID} |
104104

105105
When I run `wp menu item delete {PARENT_ID}`
106+
And I run `wp cache flush`
106107
And I run `wp menu item list grandparent-test --fields=title,db_id,menu_item_parent`
107108
Then STDOUT should be a table containing rows:
108109
| title | db_id | menu_item_parent |
@@ -195,6 +196,52 @@ Feature: Manage WordPress menu items
195196
| custom | First | 1 | https://first.com |
196197
| custom | Third | 2 | https://third.com |
197198

199+
Scenario: Menu order is recalculated on update
200+
When I run `wp menu create "Sidebar Menu"`
201+
Then STDOUT should not be empty
202+
203+
When I run `wp menu item add-custom sidebar-menu Alpha https://alpha.com --porcelain`
204+
Then save STDOUT as {ITEM_ID_1}
205+
206+
When I run `wp menu item add-custom sidebar-menu Beta https://beta.com --porcelain`
207+
Then save STDOUT as {ITEM_ID_2}
208+
209+
When I run `wp menu item add-custom sidebar-menu Gamma https://gamma.com --porcelain`
210+
Then save STDOUT as {ITEM_ID_3}
211+
212+
When I run `wp menu item list sidebar-menu --fields=type,title,position,link`
213+
Then STDOUT should be a table containing rows:
214+
| type | title | position | link |
215+
| custom | Alpha | 1 | https://alpha.com |
216+
| custom | Beta | 2 | https://beta.com |
217+
| custom | Gamma | 3 | https://gamma.com |
218+
219+
When I run `wp menu item update {ITEM_ID_3} --position=1`
220+
Then STDOUT should be:
221+
"""
222+
Success: Menu item updated.
223+
"""
224+
225+
When I run `wp menu item list sidebar-menu --fields=type,title,position,link`
226+
Then STDOUT should be a table containing rows:
227+
| type | title | position | link |
228+
| custom | Gamma | 1 | https://gamma.com |
229+
| custom | Alpha | 2 | https://alpha.com |
230+
| custom | Beta | 3 | https://beta.com |
231+
232+
When I run `wp menu item update {ITEM_ID_1} --position=3`
233+
Then STDOUT should be:
234+
"""
235+
Success: Menu item updated.
236+
"""
237+
238+
When I run `wp menu item list sidebar-menu --fields=type,title,position,link`
239+
Then STDOUT should be a table containing rows:
240+
| type | title | position | link |
241+
| custom | Gamma | 1 | https://gamma.com |
242+
| custom | Beta | 2 | https://beta.com |
243+
| custom | Alpha | 3 | https://alpha.com |
244+
198245
Scenario: Get menu item details
199246
When I run `wp menu create "Sidebar Menu"`
200247
Then STDOUT should not be empty

features/option-list.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Feature: List WordPress options
22

3+
@skip-object-cache
34
Scenario: Using the `--transients` flag
45
Given a WP install
56
And I run `wp transient set wp_transient_flag wp_transient_flag`

features/site-empty.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Feature: Empty a WordPress site of its data
7272
When I run `wp site empty --yes`
7373
Then STDOUT should be:
7474
"""
75-
Success: The site at 'https://example.com' was emptied.
75+
Success: The site at 'http://example.com' was emptied.
7676
"""
7777
And the wp-content/uploads/large-image.jpg file should exist
7878

features/term-migrate.feature

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,66 @@ Feature: Migrate term custom fields
8787
"""
8888
Error: Taxonomy term 'peach' for taxonomy 'category' doesn't exist.
8989
"""
90+
91+
@require-wp-4.4
92+
Scenario: Migrate a term when posts have been migrated to a different post type that supports the destination taxonomy
93+
Given a WP install
94+
And a wp-content/mu-plugins/test-migrate.php file:
95+
"""
96+
<?php
97+
// Plugin Name: Test Migrate
98+
99+
add_action( 'init', function() {
100+
register_post_type( 'news', [ 'public' => true ] );
101+
register_taxonomy( 'topic', 'news', [ 'public' => true ] );
102+
} );
103+
"""
104+
105+
When I run `wp term create category grape`
106+
Then STDOUT should not be empty
107+
108+
When I run `wp post create --post_title='Test post' --post_type=post --porcelain`
109+
Then STDOUT should be a number
110+
And save STDOUT as {POST_ID}
111+
112+
When I run `wp post term set {POST_ID} category grape`
113+
Then STDOUT should not be empty
114+
115+
When I run `wp post update {POST_ID} --post_type=news`
116+
Then STDOUT should not be empty
117+
118+
When I run `wp term migrate grape --by=slug --from=category --to=topic`
119+
Then STDOUT should be:
120+
"""
121+
Term 'grape' assigned to post {POST_ID}.
122+
Term 'grape' migrated.
123+
Old instance of term 'grape' removed from its original taxonomy.
124+
Success: Migrated the term 'grape' from taxonomy 'category' to taxonomy 'topic' for 1 post.
125+
"""
126+
127+
@require-wp-4.4
128+
Scenario: Migrate a term warns when post type is not registered with destination taxonomy
129+
Given a WP install
130+
131+
When I run `wp term create category grape`
132+
Then STDOUT should not be empty
133+
134+
When I run `wp post create --post_title='Test post' --post_type=post --porcelain`
135+
Then STDOUT should be a number
136+
And save STDOUT as {POST_ID}
137+
138+
When I run `wp post term set {POST_ID} category grape`
139+
Then STDOUT should not be empty
140+
141+
When I run `wp post update {POST_ID} --post_type=page`
142+
Then STDOUT should not be empty
143+
144+
When I try `wp term migrate grape --by=slug --from=category --to=post_tag`
145+
Then STDERR should contain:
146+
"""
147+
Warning: Term 'grape' not assigned to post {POST_ID}. Post type 'page' is not registered with taxonomy 'post_tag'.
148+
"""
149+
And STDOUT should contain:
150+
"""
151+
Success: Migrated the term 'grape' from taxonomy 'category' to taxonomy 'post_tag' for 0 posts.
152+
"""

features/term-recount.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Feature: Recount terms on a taxonomy
4040
"""
4141
1
4242
"""
43-
When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->term_taxonomy, array( "count" => 3 ), array( "term_id" => {TERM_ID} ) );'`
43+
When I run `wp eval 'global $wpdb; $wpdb->update( $wpdb->term_taxonomy, array( "count" => 3 ), array( "term_id" => {TERM_ID} ) ); clean_term_cache( {TERM_ID}, "category" );'`
4444
And I run `wp term get category {TERM_ID} --field=count`
4545
Then STDOUT should be:
4646
"""

phpcs.xml.dist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<!--
66
#############################################################################
77
COMMAND LINE ARGUMENTS
8-
For help understanding this file: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml
9-
For help using PHPCS: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage
8+
For help understanding this file: https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Annotated-ruleset.xml
9+
For help using PHPCS: https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Usage
1010
#############################################################################
1111
-->
1212

src/Menu_Item_Command.php

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,71 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) {
634634
}
635635

636636
$menu_item_args['menu-item-type'] = $type;
637-
$result = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args );
637+
$pending_menu_order_updates = [];
638+
639+
// Reorder other menu items when the position changes on update.
640+
if ( 'update' === $method ) {
641+
$new_position = (int) $menu_item_args['menu-item-position'];
642+
if ( $new_position > 0 ) {
643+
// Fetch all menu items sorted by their raw menu_order to determine
644+
// normalized (1-indexed) ranks, since wp_get_nav_menu_items(ARRAY_A)
645+
// normalises menu_order to 1,2,3… which may differ from the raw DB values.
646+
$sorted_item_ids = get_posts(
647+
[
648+
'post_type' => 'nav_menu_item',
649+
'numberposts' => -1,
650+
'orderby' => 'menu_order',
651+
'order' => 'ASC',
652+
'post_status' => 'any',
653+
'tax_query' => [
654+
[
655+
'taxonomy' => 'nav_menu',
656+
'field' => 'term_taxonomy_id',
657+
'terms' => $menu->term_taxonomy_id,
658+
],
659+
],
660+
'fields' => 'ids',
661+
]
662+
);
663+
664+
// Normalise to integers so that strict comparisons below work regardless of
665+
// whether $wpdb->get_col() returned strings or integers.
666+
$sorted_item_ids = array_map( 'intval', $sorted_item_ids );
667+
668+
// Clamp the requested position to the valid range of menu items.
669+
$max_position = count( $sorted_item_ids );
670+
if ( $max_position > 0 && $new_position > $max_position ) {
671+
// Treat out-of-range positions as "move to end", consistent with core behavior.
672+
$new_position = $max_position;
673+
}
674+
675+
// Find the 1-indexed normalized rank of the item being moved.
676+
$item_idx = array_search( (int) $menu_item_db_id, $sorted_item_ids, true );
677+
$old_position_normalized = ( false !== $item_idx ) ? $item_idx + 1 : 0;
678+
679+
if ( $old_position_normalized > 0 && $new_position !== $old_position_normalized ) {
680+
if ( $new_position < $old_position_normalized ) {
681+
// Moving up: items at 0-indexed [new_pos-1, old_pos-2] shift down by +1.
682+
for ( $i = $new_position - 1; $i <= $old_position_normalized - 2; $i++ ) {
683+
$pending_menu_order_updates[] = [
684+
'ID' => $sorted_item_ids[ $i ],
685+
'menu_order' => $i + 2,
686+
];
687+
}
688+
} else {
689+
// Moving down: items at 0-indexed [old_pos, new_pos-1] shift up by -1.
690+
for ( $i = $old_position_normalized; $i <= $new_position - 1; $i++ ) {
691+
$pending_menu_order_updates[] = [
692+
'ID' => $sorted_item_ids[ $i ],
693+
'menu_order' => $i,
694+
];
695+
}
696+
}
697+
}
698+
}
699+
}
700+
701+
$result = wp_update_nav_menu_item( $menu->term_id, $menu_item_db_id, $menu_item_args );
638702

639703
if ( is_wp_error( $result ) ) {
640704
WP_CLI::error( $result->get_error_message() );
@@ -645,6 +709,26 @@ private function add_or_update_item( $method, $type, $args, $assoc_args ) {
645709
WP_CLI::error( "Couldn't update menu item." );
646710
}
647711
} else {
712+
// Apply deferred reordering of other menu items only after a successful update.
713+
if ( ! empty( $pending_menu_order_updates ) ) {
714+
global $wpdb;
715+
716+
$ids_to_update = [];
717+
$case_clauses = '';
718+
foreach ( $pending_menu_order_updates as $update_args ) {
719+
$item_id = (int) $update_args['ID'];
720+
$ids_to_update[] = $item_id;
721+
$case_clauses .= $wpdb->prepare( ' WHEN %d THEN %d', $item_id, $update_args['menu_order'] );
722+
}
723+
724+
$ids_sql = implode( ',', $ids_to_update );
725+
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $case_clauses and $ids_sql are constructed from prepared/safe integer values.
726+
$wpdb->query( "UPDATE {$wpdb->posts} SET menu_order = CASE ID {$case_clauses} END WHERE ID IN ({$ids_sql})" );
727+
728+
foreach ( $ids_to_update as $id ) {
729+
clean_post_cache( $id );
730+
}
731+
}
648732

649733
if ( ( 'add' === $method ) && $menu_item_args['menu-item-position'] ) {
650734
$this->reorder_menu_items( $menu->term_id, $menu_item_args['menu-item-position'], +1, $result );

0 commit comments

Comments
 (0)