public function patch( $args, $assoc_args ) {
		list( $action, $object_id, $meta_key ) = $args;
		$object_id                             = $this->check_object_id( $object_id );
		$key_path                              = array_map(
			function( $key ) {
				if ( is_numeric( $key ) && ( (string) intval( $key ) === $key ) ) {
					return (int) $key;
				}
					return $key;
			},
			array_slice( $args, 3 )
		);

		if ( 'delete' === $action ) {
			$patch_value = null;
		} else {
			$stdin_value = EntityUtils::has_stdin()
				? trim( WP_CLI::get_value_from_arg_or_stdin( $args, -1 ) )
				: null;
			$patch_value = ! empty( $stdin_value )
				? WP_CLI::read_value( $stdin_value, $assoc_args )
				: WP_CLI::read_value( array_pop( $key_path ), $assoc_args );
		}

		/* Need to make a copy of $current_meta_value here as it is modified by reference */
		$current_meta_value = sanitize_meta( $meta_key, $this->get_metadata( $object_id, $meta_key, true ), $this->meta_type );
		$old_meta_value     = $current_meta_value;
		if ( is_object( $current_meta_value ) ) {
			$old_meta_value = clone $current_meta_value;
		}

		$traverser = new RecursiveDataStructureTraverser( $current_meta_value );

		try {
			$traverser->$action( $key_path, $patch_value );
		} catch ( Exception $exception ) {
			WP_CLI::error( $exception->getMessage() );
		}

		$patched_meta_value = sanitize_meta( $meta_key, $traverser->value(), $this->meta_type );

		if ( $patched_meta_value === $old_meta_value ) {
			WP_CLI::success( "Value passed for custom field '{$meta_key}' is unchanged." );
		} else {
			$slashed = wp_slash( $patched_meta_value );
			$success = $this->update_metadata( $object_id, $meta_key, $slashed );

			if ( $success ) {
				WP_CLI::success( "Updated custom field '{$meta_key}'." );
			} else {
				WP_CLI::error( "Failed to update custom field '{$meta_key}'." );
			}
		}
	}