`. * * @since 2.0.0 * @var string */ protected $wp_cli_command_base = ''; /** * WP-CLI Sub_command enabled for this entity. * * @since 2.0.0 * @var array */ protected $wp_cli_enabled_sub_commands = []; /** * Returns the base used right after the root. * Uses the `wp_cli_command_base` attribute if set, `slug` otherwise. * * @since 2.0.0 * @return string */ public function get_wp_cli_command_base() { return (! empty($this->wp_cli_command_base)) ? $this->wp_cli_command_base : $this->slug; } /** * Registers the routes. Should be called by the entity * to actually enable the REST API. * * @since 2.0.0 */ public function enable_wp_cli(): void { if ( ! defined('WP_CLI')) { return; } $wp_cli_root = 'wu'; $this->set_wp_cli_enabled_sub_commands(); foreach ($this->wp_cli_enabled_sub_commands as $sub_command => $sub_command_data) { \WP_CLI::add_command( "{$wp_cli_root} {$this->get_wp_cli_command_base()} {$sub_command}", $sub_command_data['callback'], [ 'synopsis' => $sub_command_data['synopsis'], ] ); } } /** * Set wP-CLI Sub-command enabled for this entity. */ public function set_wp_cli_enabled_sub_commands(): void { $sub_commands = [ 'get' => [ 'callback' => [$this, 'wp_cli_get_item'], ], 'list' => [ 'callback' => [$this, 'wp_cli_get_items'], ], 'create' => [ 'callback' => [$this, 'wp_cli_create_item'], ], 'update' => [ 'callback' => [$this, 'wp_cli_update_item'], ], 'delete' => [ 'callback' => [$this, 'wp_cli_delete_item'], ], ]; $params = array_merge($this->wp_cli_get_fields(), $this->wp_cli_extra_parameters()); $params = array_unique($params); /** * Unset undesired Params. */ $params_to_remove = apply_filters( 'wu_cli_params_to_remove', [ 'id', 'model', ] ); $params = array_filter($params, fn($param) => ! in_array($param, $params_to_remove, true)); foreach ($sub_commands as $sub_command => &$sub_command_data) { $sub_command_data['synopsis'] = []; if (in_array($sub_command, ['get', 'update', 'delete'], true)) { $sub_command_data['synopsis'][] = [ 'name' => 'id', 'type' => 'positional', 'description' => __('The id for the resource.', 'wp-ultimo'), 'optional' => false, ]; } if (in_array($sub_command, ['list', 'update', 'create'], true)) { $explanation_list = wu_rest_get_endpoint_schema($this->model_class, 'update'); foreach ($params as $name) { $explanation = wu_get_isset($explanation_list, $name, []); $type = wu_get_isset($explanation, 'type', 'assoc'); $field = [ 'name' => $name, 'description' => wu_get_isset($explanation, 'description', __('No description found.', 'wp-ultimo')), 'optional' => ! wu_get_isset($explanation, 'required'), 'type' => 'assoc', ]; $options = wu_get_isset($explanation, 'options', []); if ($options) { $field['options'] = $options; } $sub_command_data['synopsis'][] = $field; } } if (in_array($sub_command, ['create', 'update'], true)) { $sub_command_data['synopsis'][] = [ 'name' => 'porcelain', 'type' => 'flag', 'description' => __('Output just the id when the operation is successful.', 'wp-ultimo'), 'optional' => true, ]; } if (in_array($sub_command, ['list', 'get'], true)) { $sub_command_data['synopsis'][] = [ 'name' => 'format', 'type' => 'assoc', 'description' => __('Render response in a particular format.', 'wp-ultimo'), 'optional' => true, 'default' => 'table', 'options' => [ 'table', 'json', 'csv', 'ids', 'yaml', 'count', ], ]; $sub_command_data['synopsis'][] = [ 'name' => 'fields', 'type' => 'assoc', 'description' => __('Limit response to specific fields. Defaults to id, name', 'wp-ultimo'), 'optional' => true, 'options' => array_merge(['id'], $params), ]; } } $this->wp_cli_enabled_sub_commands = $sub_commands; /** * Filters which sub_commands are enabled for this entity. * * @since 2.0.0 * * @param array $sub_commands Default sub_commands. * @param string $command_base The base used in the command right after the root. * @param Base_Manager $this The object instance. */ $this->wp_cli_enabled_sub_commands = apply_filters( 'wu_wp_cli_enabled_sub_commands', $this->wp_cli_enabled_sub_commands, $this->get_wp_cli_command_base(), $this ); } /** * Allows the additional of additional parameters. * * @since 2.0.0 */ public function wp_cli_extra_parameters(): array { $model = new $this->model_class(); return array_keys($model->to_array()); } /** * Returns the list of default fields, based on the table schema. * * @since 2.0.0 * @return array List of the schema columns. */ public function wp_cli_get_fields(): array { $schema = $this->model_class::get_schema(); return array_column($schema, 'name'); } /** * Returns a specific item. * * @since 2.0.0 * * @param array $args Positional arguments passed. ID expected. * @param array $array_assoc Assoc arguments passed. */ public function wp_cli_get_item($args, $array_assoc): void { $item = $this->model_class::get_by_id($args[0]); if (empty($item)) { \WP_CLI::error('Invalid ID.'); } $fields = (! empty($array_assoc['fields'])) ? $array_assoc['fields'] : $this->wp_cli_get_fields(); $formatter = new \WP_CLI\Formatter($array_assoc, $fields); $formatter->display_item($item->to_array()); } /** * Returns a list of items. * * @since 2.0.0 * * @param array $args Positional arguments passed. ID expected. * @param array $array_assoc Assoc arguments passed. */ public function wp_cli_get_items($args, $array_assoc): void { $fields = (! empty($array_assoc['fields'])) ? $array_assoc['fields'] : $this->wp_cli_get_fields(); unset($array_assoc['fields']); $items = $this->model_class::query($array_assoc); $items = array_map(fn($item) => $item->to_array(), $items); \WP_CLI\Utils\format_items($array_assoc['format'], $items, $fields); } /** * Creates an item. * * @since 2.0.0 * * @param array $args Positional arguments passed. ID expected. * @param array $array_assoc Assoc arguments passed. */ public function wp_cli_create_item($args, $array_assoc): void { $item = new $this->model_class($array_assoc); $success = $item->save(); if (true === $success) { $item_id = $item->get_id(); if ( ! empty($array_assoc['porcelain'])) { \WP_CLI::line($item_id); } else { $message = sprintf('Item created with ID %d', $item_id); \WP_CLI::success($message); } } else { \WP_CLI::error($success); } } /** * Updates an item. * * @since 2.0.0 * * @param array $args Positional arguments passed. ID expected. * @param array $array_assoc Assoc arguments passed. */ public function wp_cli_update_item($args, $array_assoc): void { $item = $this->model_class::get_by_id($args[0]); if (empty($item)) { \WP_CLI::error('Invalid ID.'); } $porcelain = false; if ( ! empty($array_assoc['porcelain'])) { $porcelain = true; unset($array_assoc['porcelain']); } $params = $array_assoc; foreach ($params as $param => $value) { $set_method = "set_{$param}"; if ('meta' === $param) { $item->update_meta_batch($value); } elseif (method_exists($item, $set_method)) { call_user_func([$item, $set_method], $value); } else { $error_message = sprintf( /* translators: 1. Object class name; 2. Set method name */ __('The %1$s object does not have a %2$s method', 'wp-ultimo'), get_class($item), $set_method ); \WP_CLI::error($error_message); } } $success = $item->save(); if ($success) { $item_id = $item->get_id(); if ($porcelain) { \WP_CLI::line($item_id); } else { $message = sprintf('Item updated with ID %d', $item_id); \WP_CLI::success($message); } } else { \WP_CLI::error('Unexpected error. The item was not updated.'); } } /** * Deletes an item. * * @since 2.0.0 * * @param array $args Positional arguments passed. ID expected. */ public function wp_cli_delete_item($args): void { $item = $this->model_class::get_by_id($args[0]); if (empty($item)) { \WP_CLI::error('Invalid ID.'); } $success = $item->delete(); if (is_wp_error($success) || ! $success) { \WP_CLI::error('Unexpected error. The item was not deleted.'); } else { \WP_CLI::success('Item deleted.'); } } }