diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..9dc6b4df --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003 + }, + { + "name": "Launch currently open script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 0, + "runtimeArgs": [ + "-dxdebug.start_with_request=yes" + ], + "env": { + "XDEBUG_MODE": "debug,develop", + "XDEBUG_CONFIG": "client_port=${port}" + } + }, + { + "name": "Launch Built-in web server", + "type": "php", + "request": "launch", + "runtimeArgs": [ + "-dxdebug.mode=debug", + "-dxdebug.start_with_request=yes", + "-S", + "localhost:0" + ], + "program": "", + "cwd": "${workspaceRoot}", + "port": 9003, + "serverReadyAction": { + "pattern": "Development Server \\(http://localhost:([0-9]+)\\) started", + "uriFormat": "http://localhost:%s", + "action": "openExternally" + } + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 250a1139..f52fe077 100644 --- a/README.md +++ b/README.md @@ -50,5 +50,25 @@ add_filter( 'tc_skip_development_directories', '__return_true' ); To add more directories to the paths where other files are excluded then add them to the array through the `tc_common_dev_directories` filter. +### Usage with wp-cli + +To use with [wp-cli](https://wp-cli.org/), ensure the theme check plugin is active and `wp-cli` is installed. The `theme-check` subcommand is added to `wp-cli` and can be used as follows: + +`wp theme-check run [] [--format=]` + +On success, the command returns a formatted table of results from the theme check plugin. + +#### Options +| Option | Accepts | Required | Default +| -- | -- | -- | -- | +| `theme` | The slug of the theme to check | No | Current theme slug +| `format` | `cli` or `json` | No | `cli` + +#### Examples +`wp theme-check run` +`wp theme-check run twentytwentyfour` +`wp theme-check run --format=json` +`wp theme-check run twentytwentyfour --format=json` + ## Contributors Otto42, pross, The theme review team diff --git a/theme-check.php b/theme-check.php index a8e45451..aaa818e7 100644 --- a/theme-check.php +++ b/theme-check.php @@ -14,6 +14,10 @@ class ThemeCheckMain { function __construct() { add_action( 'admin_init', array( $this, 'tc_i18n' ) ); add_action( 'admin_menu', array( $this, 'themecheck_add_page' ) ); + + if ( defined( 'WP_CLI' ) && WP_CLI ) { + include 'wp-cli/class-theme-check-cli.php'; + } } function tc_i18n() { diff --git a/wp-cli/class-theme-check-cli.php b/wp-cli/class-theme-check-cli.php new file mode 100644 index 00000000..603f8262 --- /dev/null +++ b/wp-cli/class-theme-check-cli.php @@ -0,0 +1,120 @@ +] + * : The slug of the theme to check. If not provided, checks the current theme. + * + * [--format=] + * : Render output in a particular format. + * --- + * default: table + * options: + * - table + * - json + * --- + * + * ## EXAMPLES + * # Check the current active theme + * wp theme-check run + * + * # Check a specific theme + * wp theme-check run twentytwentyfour + * + * # Check the current active theme and output results as JSON + * wp theme-check run --format=json + * + * # Check a specific theme and output results as JSON + * wp theme-check run twentytwentyfour --format=json + * + * @param array $args Indexed array of positional arguments. + * @param array $assoc_args Associative array of options. + * @return void + */ + public function run( $args, $assoc_args ) { + $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' ); + + // Get the current theme + $current_theme = wp_get_theme(); + $current_theme_slug = $current_theme->get_stylesheet(); + + // Use the provided theme slug if available, otherwise use the current theme + $check_theme_slug = ! empty( $args[0] ) ? $args[0] : $current_theme_slug; + + // Get the theme + $theme = wp_get_theme( $check_theme_slug ); + + if ( ! $theme->exists() ) { + WP_CLI::error( "Theme '{$check_theme_slug}' not found." ); + } + + // Run the checks + $success = run_themechecks_against_theme( $theme, $check_theme_slug ); + $processed_messages = $this->process_themecheck_messages(); + + WP_CLI\Utils\format_items( $format, $processed_messages, array( 'type', 'value' ) ); + + // Set the exit code based on $success + WP_CLI::halt( $success ? 0 : 1 ); + } + + /** + * Process theme check messages. + * + * @return array Processed messages. + */ + private function process_themecheck_messages() { + global $themechecks; + $messages = array(); + + foreach ( $themechecks as $check ) { + if ( $check instanceof themecheck ) { + $error = $check->getError(); + $error = (array) $error; + if ( ! empty( $error ) ) { + $messages = array_merge( $messages, $error ); + } + } + } + + $processed_messages = array_map( + function( $message ) { + if ( preg_match( '/]*>(.*?)<\/span>(.*)/', $message, $matches ) ) { + $key = $matches[1]; + $value = $matches[2]; + } else { + $key = ''; + $value = $message; + } + + $key = wp_strip_all_tags( $key ); + $key = html_entity_decode( $key, ENT_QUOTES, 'UTF-8' ); + $key = rtrim( $key, ':' ); + + $value = wp_strip_all_tags( $value ); + $value = html_entity_decode( $value, ENT_QUOTES, 'UTF-8' ); + $value = ltrim( $value, ': ' ); + + return array( + 'type' => trim( $key ), + 'value' => trim( $value ), + ); + }, + $messages + ); + + return $processed_messages; + } +}