] * : The backup profile to use. Default: 1. * * [--filter=] * : Only return records whose keys begin with the given filter * * [--sort-by=] * : Sort the output by the given column. * --- * default: none * options: * - none * - key * - value * - type * - default * - title * - description * - section * --- * * [--sort-order=] * : Sort order * --- * default: asc * options: * - asc * - desc * --- * * [--format=] * : The format for the returned list * --- * default: table * options: * - table * - json * - csv * - yaml * - count * --- * * ## EXAMPLES * * wp akeeba option list * * wp akeeba option list --profile=2 --format=json * * wp akeeba option list --profile=2 --filter="core." --sort-by=key --sort-order=desc * * @when after_wp_load * @subcommand list * * @param array $args Positional arguments (literal arguments) * @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value) * * @return void * * @throws WP_CLI\ExitException * * @since 3.0.0 */ public function _list($args, $assoc_args) { /** @var Application $akeebaBackupApplication */ global $akeebaBackupApplication; $container = $akeebaBackupApplication->getContainer(); $format = isset($assoc_args['format']) ? $assoc_args['format'] : 'table'; $profileID = isset($assoc_args['profile']) ? (int) $assoc_args['profile'] : 1; $profileID = max(1, $profileID); /** @var \Solo\Model\Profiles $model */ $model = Model::getTmpInstance($container->application_name, 'Profiles', $container); try { $model->findOrFail($profileID); } catch (Exception $e) { WP_CLI::error("Could not find profile #$profileID."); } unset($model); // Get the profile's configuration Platform::getInstance()->load_configuration($profileID); $config = Factory::getConfiguration(); $rawJson = $config->exportAsJSON(); unset($config); // Get the key information from the GUI data $info = $this->parseJsonGuiData(); // Convert the INI data we got into an array we can print $rawValues = json_decode($rawJson, true); unset($rawJson); $output = []; $rawValues = $this->flattenOptions($rawValues); foreach ($rawValues as $key => $v) { $output[$key] = array_merge([ 'key' => $key, 'value' => $v, 'title' => '', 'description' => '', 'type' => '', 'default' => '', 'section' => '', 'options' => [], 'optionTitles' => [], 'limits' => [], ], $this->getOptionInfo($key, $info)); } // Filter the returned options $filter = isset($assoc_args['filter']) ? $assoc_args['filter'] : ''; $output = array_filter($output, function ($item) use ($filter) { if (!empty($filter) && strpos($item['key'], $filter) !== 0) { return false; } return $item['type'] != 'hidden'; }); // Sort the results $sort = isset($assoc_args['sort-by']) ? $assoc_args['sort-by'] : 'none'; $order = isset($assoc_args['sort-order']) ? $assoc_args['sort-order'] : 'asc'; if ($sort != 'none') { usort($output, function ($a, $b) use ($sort, $order) { if ($a[$sort] == $b[$sort]) { return 0; } $signChange = ($order == 'asc') ? 1 : -1; $isGreater = $a[$sort] > $b[$sort] ? 1 : -1; return $signChange * $isGreater; }); } // Output the list if (empty($output)) { WP_CLI::error("No options found matching your criteria."); } $keys = array_keys($output); $firstKey = array_shift($keys); CliUtils\format_items($format, $output, array_keys($output[$firstKey])); } /** * Gets the value of a configuration option for an Akeeba Backup profile * * ## OPTIONS * * * : The option key to retrieve * * [--profile=] * : The backup profile to use. Default: 1. * * [--format=] * : The format for the returned value * --- * default: text * options: * - text * - json * - print_r * - var_dump * - var_export * --- * * ## EXAMPLES * * wp akeeba option get akeeba.basic.archive_name * * wp akeeba option get akeeba.basic.archive_name --profile=2 * * wp akeeba option get akeeba.basic.archive_name --profile=2 --format=var_export * * @when after_wp_load * * @param array $args Positional arguments (literal arguments) * @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value) * * @return void * * @throws WP_CLI\ExitException * * @since 3.0.0 */ public function get($args, $assoc_args) { $key = isset($args[0]) ? $args[0] : null; if (empty($key)) { WP_CLI::error("You must specify the option key to retrieve."); } /** @var Application $akeebaBackupApplication */ global $akeebaBackupApplication; $container = $akeebaBackupApplication->getContainer(); $profileID = isset($assoc_args['profile']) ? (int) $assoc_args['profile'] : 1; $profileID = max(1, $profileID); /** @var \Solo\Model\Profiles $model */ $model = Model::getTmpInstance($container->application_name, 'Profiles', $container); try { $model->findOrFail($profileID); } catch (Exception $e) { WP_CLI::error("Could not find profile #$profileID."); } unset($model); // Get the profile's configuration Platform::getInstance()->load_configuration($profileID); $config = Factory::getConfiguration(); $value = $config->get($key, '', false); switch ($assoc_args['format']) { case 'text': default: echo $value; break; case 'json': echo json_encode($value); break; case 'print_r': print_r($value); break; case 'var_dump': var_dump($value); break; case 'var_export': var_export($value); break; } } /** * Sets the value of a configuration option for an Akeeba Backup profile * * ## OPTIONS * * * : The option key to set * * * : The value to set * * [--profile=] * : The backup profile to use. Default: 1. * * [--force] * : Allow setting of protected options. * * ## EXAMPLES * * wp akeeba option set akeeba.basic.archive_name "site-[HOST]-[DATE]-[TIME]" * * wp akeeba option set akeeba.basic.archive_name "site-[HOST]-[DATE]-[TIME]" --profile=2 * * @when after_wp_load * * @param array $args Positional arguments (literal arguments) * @param array $assoc_args Associative arguments (--flag, --no-flag, --key=value) * * @return void * * @throws WP_CLI\ExitException * * @since 3.0.0 */ public function set($args, $assoc_args) { $key = isset($args[0]) ? $args[0] : null; $value = isset($args[1]) ? $args[1] : null; if (empty($key)) { WP_CLI::error("You must specify the option key to set."); } if (is_null($value)) { WP_CLI::error("You must specify the option value to set."); } /** @var Application $akeebaBackupApplication */ global $akeebaBackupApplication; $container = $akeebaBackupApplication->getContainer(); $profileID = isset($assoc_args['profile']) ? (int) $assoc_args['profile'] : 1; $profileID = max(1, $profileID); /** @var \Solo\Model\Profiles $model */ $model = Model::getTmpInstance($container->application_name, 'Profiles', $container); try { $model->findOrFail($profileID); } catch (Exception $e) { WP_CLI::error("Could not find profile #$profileID."); } unset($model); // Get the profile's configuration Platform::getInstance()->load_configuration($profileID); $config = Factory::getConfiguration(); // Get the key information from the GUI data $info = $this->parseJsonGuiData(); // Does the key exist? if (!array_key_exists($key, $info['options'])) { WP_CLI::error("Invalid option key '$key'."); } // Validate / sanitize the value $optionInfo = $this->getOptionInfo($key, $info); switch ($optionInfo['type']) { case 'integer': $value = (int) $value; if (($value < $optionInfo['limits']['min']) || ($value > $optionInfo['limits']['max'])) { WP_CLI::error("Invalid value '$value': out of bounds."); } break; case 'bool': if (is_numeric($value)) { $value = (int) $value; } elseif (is_string($value)) { $value = strtolower($value); } if (in_array($value, [false, 0, '0', 'false', 'no', 'off'], true)) { $value = 0; } elseif (in_array($value, [true, 1, '1', 'true', 'yes', 'on'], true)) { $value = 1; } else { WP_CLI::error("Invalid boolean value '$value': use one of 0, false, no, off, 1, true, yes or on.'"); } break; case 'enum': if (!in_array($value, $optionInfo['options'])) { $options = array_map(function ($v) { return "'$v'"; }, $optionInfo['options']); $options = implode(', ', $options); WP_CLI::error("Invalid enumerated value '$value'. Must be one of $options."); } break; case 'hidden': WP_CLI::error("Setting hidden option '$key' is not allowed."); break; case 'string': break; default: WP_CLI::error("Unknown type {$optionInfo['type']} for option '$key'. Have you manually tampered with the option INI files?"); break; } $protected = $config->getProtectedKeys(); $force = isset($assoc_args['force']) && $assoc_args['force']; if (in_array($key, $protected) && !$force) { WP_CLI::error("Cannot set protected option '$key'. Please use the --force option to override the protection."); } if (in_array($key, $protected) && $force) { $config->setKeyProtection($key, false); } $result = $config->set($key, $value, false); if ($result === false) { WP_CLI::error("Could not set option '$key'."); } Platform::getInstance()->save_configuration($profileID); WP_CLI::success("Successfully set option '$key' to '$value'"); } /** * Parse the JSON GUI definition returned by Akeeba Engine into something I can use to provide information about * the options. * * @return array * * @since 3.0.0 */ private function parseJsonGuiData() { $jsonGUIData = Factory::getEngineParamsProvider()->getJsonGuiDefinition(); $guiData = json_decode($jsonGUIData, true); $ret = [ 'engines' => [], 'installers' => [], 'options' => [], ]; // Parse engines foreach ($guiData['engines'] as $engineType => $engineRecords) { if (!isset($ret['engines'][$engineType])) { $ret['engines'][$engineType] = []; } foreach ($engineRecords as $engineName => $record) { $ret['engines'][$engineType][$engineName] = [ 'title' => $record['information']['title'], 'description' => $record['information']['description'], ]; foreach ($record['parameters'] as $key => $optionRecord) { $ret['options'][$key] = array_merge($optionRecord, [ 'section' => $record['information']['title'], ]); } } } // Parse installers foreach ($guiData['installers'] as $installerName => $installerInfo) { $ret['installers'][$installerName] = $installerInfo['name']; } // Parse GUI sections foreach ($guiData['gui'] as $section => $options) { foreach ($options as $key => $optionRecord) { $ret['options'][$key] = array_merge($optionRecord, [ 'section' => $section, ]); } } return $ret; } /** * Get the information for an option record. * * @param string $key The option key * @param array $info The array returned by parseJsonGuiData * * @return array * * @since 3.0.0 */ private function getOptionInfo($key, &$info) { $ret = []; if (!isset($info['options'][$key])) { return $ret; } $keyInfo = $info['options'][$key]; $ret = [ 'title' => $keyInfo['title'], 'description' => $keyInfo['description'], 'section' => $keyInfo['section'], 'type' => $keyInfo['type'], 'default' => $keyInfo['default'], 'options' => [], 'optionTitles' => [], 'limits' => [], ]; switch ($keyInfo['type']) { case 'integer': if (isset($keyInfo['shortcuts'])) { $ret['options'] = explode('|', $keyInfo['shortcuts']); } $ret['limits'] = [ 'min' => $keyInfo['min'], 'max' => $keyInfo['max'], ]; break; case 'bool': $ret['type'] = 'integer'; $ret['options'] = [0, 1]; $ret['limits'] = [ 'min' => 0, 'max' => 1, ]; break; case 'engine': $ret['type'] = 'enum'; $ret['type'] = 'string'; $ret['options'] = array_keys($info['engines'][$keyInfo['subtype']]); $ret['optionTitles'] = []; foreach ($info['engines'][$keyInfo['subtype']] as $k => $details) { $ret['optionTitles'][$k] = $details['title']; } break; case 'installer': $ret['type'] = 'enum'; $ret['type'] = 'string'; $ret['options'] = array_keys($info['installers']); $ret['optionTitles'] = $info['installers']; break; case 'enum': $ret['type'] = 'string'; $ret['options'] = explode('|', $keyInfo['enumvalues']); $ret['optionTitles'] = explode('|', $keyInfo['enumkeys']); break; case 'hidden': case 'button': case 'separator': $ret['type'] = 'hidden'; break; case 'string': case 'browsedir': case 'password': default: $ret['type'] = 'string'; break; } return $ret; } /** * Flattens the option tree returned by exportToJson into an array with dotted notation for each option. * * @param array $rawOptions The option tree * @param string $prefix Current prefix, used for recursion * * @return array */ private function flattenOptions(array $rawOptions, $prefix = '') { $ret = []; foreach ($rawOptions as $k => $v) { if (is_array($v)) { $ret = array_merge($ret, $this->flattenOptions($v, $prefix . $k . '.')); continue; } $ret[$prefix . $k] = $v; } return $ret; } }