diff --git a/features/post.feature b/features/post.feature index 09e6ef449..c480a6f93 100644 --- a/features/post.feature +++ b/features/post.feature @@ -422,6 +422,36 @@ Feature: Manage WordPress posts post-2 """ + Scenario: Creating/updating posts with taxonomies + When I run `wp term create category "First Category" --porcelain` + And save STDOUT as {CAT_1} + And I run `wp term create category "Second Category" --porcelain` + And save STDOUT as {CAT_2} + And I run `wp term create post_tag "Term One" --porcelain` + And I run `wp term create post_tag "Term Two" --porcelain` + And I run `wp post create --post_title='Test Post' --post_content='Test post content' --tax_input='{"category":[{CAT_1},{CAT_2}],"post_tag":["term-one", "term-two"]}' --porcelain` + Then STDOUT should be a number + And save STDOUT as {POST_ID} + + When I run `wp post term list {POST_ID} category post_tag --format=table --fields=name,taxonomy` + Then STDOUT should be a table containing rows: + | name | taxonomy | + | First Category | category | + | Second Category | category | + | Term One | post_tag | + | Term Two | post_tag | + When I run `wp post update {POST_ID} --tax_input='{"category":[{CAT_1}],"post_tag":["term-one"]}'` + Then STDOUT should contain: + """ + Success: Updated post {POST_ID}. + """ + + When I run `wp post term list {POST_ID} category post_tag --format=table --fields=name,taxonomy` + Then STDOUT should be a table containing rows: + | name | taxonomy | + | First Category | category | + | Term One | post_tag | + Scenario: Update categories on a post When I run `wp term create category "Test Category" --porcelain` Then save STDOUT as {TERM_ID} diff --git a/src/Post_Command.php b/src/Post_Command.php index 3d85dcc37..5e10c546b 100644 --- a/src/Post_Command.php +++ b/src/Post_Command.php @@ -122,6 +122,8 @@ public function __construct() { * [--tax_input=] * : Array of taxonomy terms keyed by their taxonomy name. Default empty. * + * 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 + * * [--meta_input=] * : Array in JSON format of post meta values keyed by their post meta key. Default empty. * @@ -183,7 +185,7 @@ public function create( $args, $assoc_args ) { $assoc_args['post_category'] = $this->get_category_ids( $assoc_args['post_category'] ); } - $array_arguments = [ 'meta_input' ]; + $array_arguments = [ 'meta_input', 'tax_input' ]; $assoc_args = Utils\parse_shell_arrays( $assoc_args, $array_arguments ); if ( isset( $assoc_args['from-post'] ) ) { @@ -212,7 +214,41 @@ public function create( $args, $assoc_args ) { $args, $assoc_args, function ( $params ) { - return wp_insert_post( $params, true ); + $filter_callback = null; + + if ( 0 === get_current_user_id() && ! empty( $params['tax_input'] ) ) { + $allowed_caps = []; + /** + * @var string $taxonomy + */ + foreach ( array_keys( $params['tax_input'] ) as $taxonomy ) { + $tax_obj = get_taxonomy( $taxonomy ); + if ( $tax_obj ) { + $primitive_caps = map_meta_cap( $tax_obj->cap->assign_terms, 0 ); + $allowed_caps = array_merge( $allowed_caps, $primitive_caps ); + } + } + + if ( ! empty( $allowed_caps ) ) { + $filter_callback = function ( $allcaps, $caps ) use ( $allowed_caps ) { + foreach ( $caps as $cap ) { + if ( in_array( $cap, $allowed_caps, true ) ) { + $allcaps[ $cap ] = true; + } + } + return $allcaps; + }; + add_filter( 'user_has_cap', $filter_callback, 10, 2 ); + } + } + + $result = wp_insert_post( $params, true ); + + if ( $filter_callback ) { + remove_filter( 'user_has_cap', $filter_callback ); + } + + return $result; } ); } @@ -297,6 +333,8 @@ function ( $params ) { * [--tax_input=] * : Array of taxonomy terms keyed by their taxonomy name. Default empty. * + * 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 + * * [--meta_input=] * : Array in JSON format of post meta values keyed by their post meta key. Default empty. * @@ -348,7 +386,7 @@ public function update( $args, $assoc_args ) { $assoc_args['post_category'] = $this->get_category_ids( $assoc_args['post_category'] ); } - $array_arguments = [ 'meta_input' ]; + $array_arguments = [ 'meta_input', 'tax_input' ]; $assoc_args = Utils\parse_shell_arrays( $assoc_args, $array_arguments ); $assoc_args = wp_slash( $assoc_args ); @@ -356,7 +394,41 @@ public function update( $args, $assoc_args ) { $args, $assoc_args, function ( $params ) { - return wp_update_post( $params, true ); + $filter_callback = null; + + if ( 0 === get_current_user_id() && ! empty( $params['tax_input'] ) ) { + $allowed_caps = []; + /** + * @var string $taxonomy + */ + foreach ( array_keys( $params['tax_input'] ) as $taxonomy ) { + $tax_obj = get_taxonomy( $taxonomy ); + if ( $tax_obj ) { + $primitive_caps = map_meta_cap( $tax_obj->cap->assign_terms, 0 ); + $allowed_caps = array_merge( $allowed_caps, $primitive_caps ); + } + } + + if ( ! empty( $allowed_caps ) ) { + $filter_callback = function ( $allcaps, $caps ) use ( $allowed_caps ) { + foreach ( $caps as $cap ) { + if ( in_array( $cap, $allowed_caps, true ) ) { + $allcaps[ $cap ] = true; + } + } + return $allcaps; + }; + add_filter( 'user_has_cap', $filter_callback, 10, 2 ); + } + } + + $result = wp_update_post( $params, true ); + + if ( $filter_callback ) { + remove_filter( 'user_has_cap', $filter_callback ); + } + + return $result; } ); }