. * @since 2.0.0 */ namespace OPcacheManager\Plugin\Feature; use OPcacheManager\System\OPcache; use OPcacheManager\System\Environment; use OPcacheManager\System\Option; use OPcacheManager\Plugin\Feature\Analytics; use OPcacheManager\System\Markdown; use OPcacheManager\Plugin\Opcache_Manager_Admin; use Spyc; /** * Manages OPcache and get analytics about its use. * * @package Features * @author Pierre Lannoy . * @since 2.0.0 */ class Wpcli { /** * List of exit codes. * * @since 2.0.0 * @var array $exit_codes Exit codes. */ private $exit_codes = [ 0 => 'operation successful.', 1 => 'unrecognized setting.', 2 => 'unrecognized action.', 3 => 'analytics are disabled.', 4 => 'invalidation or warmup already scheduled.', 255 => 'unknown error.', ]; /** * Write ids as clean stdout. * * @param array $ids The ids. * @param string $field Optional. The field to output. * @since 2.0.0 */ private function write_ids( $ids, $field = '' ) { $result = ''; $last = end( $ids ); foreach ( $ids as $key => $id ) { if ( '' === $field ) { $result .= $key; } else { $result .= $id[ $field ]; } if ( $id !== $last ) { $result .= ' '; } } // phpcs:ignore fwrite( STDOUT, $result ); } /** * Write an error. * * @param integer $code Optional. The error code. * @param boolean $stdout Optional. Clean stdout output. * @since 2.0.0 */ private function error( $code = 255, $stdout = false ) { $msg = '[' . OPCM_PRODUCT_NAME . '] ' . ucfirst( $this->exit_codes[ $code ] ); if ( \WP_CLI\Utils\isPiped() ) { // phpcs:ignore fwrite( STDOUT, '' ); // phpcs:ignore exit( $code ); } elseif ( $stdout ) { // phpcs:ignore fwrite( STDERR, $msg ); // phpcs:ignore exit( $code ); } else { \WP_CLI::error( $msg ); } } /** * Write a warning. * * @param string $msg The message. * @param string $result Optional. The result. * @param boolean $stdout Optional. Clean stdout output. * @since 2.0.0 */ private function warning( $msg, $result = '', $stdout = false ) { $msg = '[' . OPCM_PRODUCT_NAME . '] ' . ucfirst( $msg ); if ( \WP_CLI\Utils\isPiped() || $stdout ) { // phpcs:ignore fwrite( STDOUT, $result ); } else { \WP_CLI::warning( $msg ); } } /** * Write a success. * * @param string $msg The message. * @param string $result Optional. The result. * @param boolean $stdout Optional. Clean stdout output. * @since 2.0.0 */ private function success( $msg, $result = '', $stdout = false ) { $msg = '[' . OPCM_PRODUCT_NAME . '] ' . ucfirst( $msg ); if ( \WP_CLI\Utils\isPiped() || $stdout ) { // phpcs:ignore fwrite( STDOUT, $result ); } else { \WP_CLI::success( $msg ); } } /** * Write a wimple line. * * @param string $msg The message. * @param string $result Optional. The result. * @param boolean $stdout Optional. Clean stdout output. * @since 2.0.0 */ private function line( $msg, $result = '', $stdout = false ) { if ( \WP_CLI\Utils\isPiped() || $stdout ) { // phpcs:ignore fwrite( STDOUT, $result ); } else { \WP_CLI::line( $msg ); } } /** * Write a wimple log line. * * @param string $msg The message. * @param boolean $stdout Optional. Clean stdout output. * @since 2.0.0 */ private function log( $msg, $stdout = false ) { if ( ! \WP_CLI\Utils\isPiped() && ! $stdout ) { \WP_CLI::log( $msg ); } } /** * Get params from command line. * * @param array $args The command line parameters. * @return array The true parameters. * @since 2.0.0 */ private function get_params( $args ) { $result = ''; if ( array_key_exists( 'settings', $args ) ) { $result = \json_decode( $args['settings'], true ); } if ( ! $result || ! is_array( $result ) ) { $result = []; } return $result; } /** * Get OPcache Manager details and operation modes. * * ## EXAMPLES * * wp opcache status * * * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-opcache-manager/blob/master/WP-CLI.md === * */ public function status( $args, $assoc_args ) { \WP_CLI::line( sprintf( '%s is running.', Environment::plugin_version_text() ) ); $name = OPcache::name(); if ( '' === $name ) { \WP_CLI::line( 'OPcache is not activated for command-line.' ); } else { \WP_CLI::line( sprintf( '%s is activated for command-line.', $name ) ); } if ( 'reset' === Option::network_get( 'reset_frequency' ) ) { \WP_CLI::line( 'Site invalidation: disabled.' ); } else { $message = 'Site invalidation: '; foreach ( Opcache_Manager_Admin::get_frequencies() as $f ) { if ( $f[0] === Option::network_get( 'reset_frequency' ) ) { $message .= $f[1]; } } if ( Option::network_get( 'warmup' ) ) { $message .= ' - followed by site warm-up'; } \WP_CLI::line( $message . '.' ); } if ( Option::network_get( 'analytics' ) ) { \WP_CLI::line( 'Analytics: enabled.' ); } else { \WP_CLI::line( 'Analytics: disabled.' ); } if ( Option::network_get( 'metrics' ) ) { \WP_CLI::line( 'Metrics collation: enabled.' ); } else { \WP_CLI::line( 'Metrics collation: disabled.' ); } if ( \DecaLog\Engine::isDecalogActivated() ) { \WP_CLI::line( 'Logging support: ' . \DecaLog\Engine::getVersionString() . '.' ); } else { \WP_CLI::line( 'Logging support: no.' ); } } /** * Modify OPcache Manager main settings. * * ## OPTIONS * * * : The action to take. * * * : The setting to change. * * [--yes] * : Answer yes to the confirmation message, if any. * * [--stdout] * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by OPcache Manager. * * ## EXAMPLES * * wp opcache settings enable analytics * * * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-opcache-manager/blob/master/WP-CLI.md === * */ public function settings( $args, $assoc_args ) { $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false ); $action = isset( $args[0] ) ? (string) $args[0] : ''; $setting = isset( $args[1] ) ? (string) $args[1] : ''; switch ( $action ) { case 'enable': switch ( $setting ) { case 'analytics': Option::network_set( 'analytics', true ); $this->success( 'analytics are now activated.', '', $stdout ); break; case 'metrics': Option::network_set( 'metrics', true ); $this->success( 'metrics collation is now activated.', '', $stdout ); break; default: $this->error( 1, $stdout ); } break; case 'disable': switch ( $setting ) { case 'analytics': \WP_CLI::confirm( 'Are you sure you want to deactivate analytics?', $assoc_args ); Option::network_set( 'analytics', false ); $this->success( 'analytics are now deactivated.', '', $stdout ); break; case 'metrics': \WP_CLI::confirm( 'Are you sure you want to deactivate metrics collation?', $assoc_args ); Option::network_set( 'metrics', false ); $this->success( 'metrics collation is now deactivated.', '', $stdout ); break; default: $this->error( 1, $stdout ); } break; default: $this->error( 2, $stdout ); } } /** * Get OPcache analytics for today. * * ## OPTIONS * * [--format=] * : Set the output format. Note if json or yaml is chosen: full metadata is outputted too. * --- * default: table * options: * - table * - json * - csv * - yaml * - count * --- * * [--stdout] * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by OPcache Manager. * * ## EXAMPLES * * wp opcache analytics * * * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-opcache-manager/blob/master/WP-CLI.md === * */ public function analytics( $args, $assoc_args ) { $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false ); if ( ! Option::network_get( 'analytics' ) ) { $this->error( 3, $stdout ); } $analytics = Analytics::get_status_kpi_collection(); $result = []; if ( array_key_exists( 'data', $analytics ) ) { foreach ( $analytics['data'] as $kpi ) { $item = []; $item['kpi'] = $kpi['name']; $item['description'] = $kpi['description']; $item['value'] = $kpi['value']['human']; if ( array_key_exists( 'ratio', $kpi ) && isset( $kpi['ratio'] ) ) { $item['ratio'] = $kpi['ratio']['percent'] . '%'; } else { $item['ratio'] = '-'; } $item['variation'] = ( 0 < $kpi['variation']['percent'] ? '+' : '' ) . (string) $kpi['variation']['percent'] . '%'; $result[] = $item; } } $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' ); if ( 'json' === $format ) { $detail = wp_json_encode( $analytics ); $this->line( $detail, $detail, $stdout ); } elseif ( 'yaml' === $format ) { unset( $analytics['assets'] ); $detail = Spyc::YAMLDump( $analytics, true, true, true ); $this->line( $detail, $detail, $stdout ); } else { \WP_CLI\Utils\format_items( $assoc_args['format'], $result, [ 'kpi', 'description', 'value', 'ratio', 'variation' ] ); } } /** * Get information on exit codes. * * ## OPTIONS * * * : The action to take. * --- * options: * - list * --- * * [--format=] * : Allows overriding the output of the command when listing exit codes. * --- * default: table * options: * - table * - json * - csv * - yaml * - ids * - count * --- * * ## EXAMPLES * * Lists available exit codes: * + wp opcache exitcode list * + wp opcache exitcode list --format=json * * * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-traffic/blob/master/WP-CLI.md === * */ public function exitcode( $args, $assoc_args ) { $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false ); $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' ); $action = isset( $args[0] ) ? $args[0] : 'list'; $codes = []; foreach ( $this->exit_codes as $key => $msg ) { $codes[ $key ] = [ 'code' => $key, 'meaning' => ucfirst( $msg ), ]; } switch ( $action ) { case 'list': if ( 'ids' === $format ) { $this->write_ids( $codes ); } else { \WP_CLI\Utils\format_items( $format, $codes, [ 'code', 'meaning' ] ); } break; } } /** * Schedules an immediate invalidation. * * [--yes] * : Answer yes to the confirmation message, if any. * * [--stdout] * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by OPcache Manager. * * ## EXAMPLES * * Invalidate all site/network files: * + wp opcache invalidate * * * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-traffic/blob/master/WP-CLI.md === * */ public function invalidate( $args, $assoc_args ) { $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false ); $invalidate = Option::network_get( 'flash_invalidate' ); $warmup = Option::network_get( 'flash_warmup' ); if ( $invalidate || $warmup ) { $this->error( 4, $stdout ); } else { \WP_CLI::confirm( 'Are you sure you want to schedule a full invalidation?', $assoc_args ); Option::network_set( 'flash_invalidate', true ); $this->success( 'invalidation scheduled to start in less than 5 minutes.', '', $stdout ); } } /** * Schedules an immediate invalidation followed by a warmup. * * [--yes] * : Answer yes to the confirmation message, if any. * * [--stdout] * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by OPcache Manager. * * ## EXAMPLES * * Invalidate and warmup all site/network files: * + wp opcache warmup * * * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-traffic/blob/master/WP-CLI.md === * */ public function warmup( $args, $assoc_args ) { $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false ); $invalidate = Option::network_get( 'flash_invalidate' ); $warmup = Option::network_get( 'flash_warmup' ); if ( $invalidate || $warmup ) { $this->error( 4, $stdout ); } else { \WP_CLI::confirm( 'Are you sure you want to schedule a full invalidation followed by a warmup?', $assoc_args ); Option::network_set( 'flash_warmup', true ); $this->success( 'invalidation and warmup scheduled to start in less than 5 minutes.', '', $stdout ); } } /** * Get the WP-CLI help file. * * @param array $attributes 'style' => 'markdown', 'html'. * 'mode' => 'raw', 'clean'. * @return string The output of the shortcode, ready to print. * @since 1.0.0 */ public static function sc_get_helpfile( $attributes ) { $md = new Markdown(); return $md->get_shortcode( 'WP-CLI.md', $attributes ); } } add_shortcode( 'opcm-wpcli', [ 'OPcacheManager\Plugin\Feature\Wpcli', 'sc_get_helpfile' ] ); if ( defined( 'WP_CLI' ) && WP_CLI ) { \WP_CLI::add_command( 'opcache', 'OPcacheManager\Plugin\Feature\Wpcli' ); }