From 6ddb7549e0cab7f7bedfe9b4cae1d7378ddcd6ed Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Mon, 23 Oct 2023 15:06:48 +0530 Subject: [PATCH 01/10] Add link to Plugin Editor --- assets/js/plugin-check-admin.js | 2 + includes/Admin/Admin_Page.php | 36 ++++++ includes/Checker/Check_Result.php | 2 + includes/Traits/Amend_Check_Result.php | 3 + includes/Traits/File_Editor_URL.php | 116 +++++++++++++++++++ phpstan.neon.dist | 1 + templates/results-row.php | 5 + templates/results-table.php | 1 + tests/phpunit/Checker/Check_Result_Tests.php | 4 + 9 files changed, 170 insertions(+) create mode 100644 includes/Traits/File_Editor_URL.php diff --git a/assets/js/plugin-check-admin.js b/assets/js/plugin-check-admin.js index 089b32bf8..f2ae221f0 100644 --- a/assets/js/plugin-check-admin.js +++ b/assets/js/plugin-check-admin.js @@ -385,6 +385,7 @@ for ( let i = 0; i < results[ line ][ column ].length; i++ ) { const message = results[ line ][ column ][ i ].message; const code = results[ line ][ column ][ i ].code; + const link = results[ line ][ column ][ i ].link; table.innerHTML += renderTemplate( 'plugin-check-results-row', @@ -394,6 +395,7 @@ type, message, code, + link, } ); } diff --git a/includes/Admin/Admin_Page.php b/includes/Admin/Admin_Page.php index 51588bdef..c942633c5 100644 --- a/includes/Admin/Admin_Page.php +++ b/includes/Admin/Admin_Page.php @@ -51,6 +51,7 @@ public function __construct( Admin_AJAX $admin_ajax ) { public function add_hooks() { add_action( 'admin_menu', array( $this, 'add_and_initialize_page' ) ); add_filter( 'plugin_action_links', array( $this, 'filter_plugin_action_links' ), 10, 4 ); + add_action( 'admin_enqueue_scripts', array( $this, 'add_jump_to_line_code_editor' ) ); $this->admin_ajax->add_hooks(); } @@ -123,6 +124,41 @@ public function enqueue_scripts() { ); } + /** + * Enqueue a script in the WordPress admin on plugin-editor.php. + * + * @since n.e.x.t + * + * @param string $hook_suffix The current admin page. + */ + public function add_jump_to_line_code_editor( $hook_suffix ) { + if ( 'plugin-editor.php' !== $hook_suffix ) { + return; + } + + $line = (int) ( $_GET['line'] ?? 0 ); + if ( ! $line ) { + return; + } + + wp_add_inline_script( + 'wp-theme-plugin-editor', + sprintf( + ' + ( + ( originalInitCodeEditor ) => { + wp.themePluginEditor.initCodeEditor = function() { + originalInitCodeEditor.apply( this, arguments ); + this.instance.codemirror.doc.setCursor( %d - 1 ); + }; + } + )( wp.themePluginEditor.initCodeEditor ); + ', + wp_json_encode( $line ) + ) + ); + } + /** * Returns the list of plugins. * diff --git a/includes/Checker/Check_Result.php b/includes/Checker/Check_Result.php index c06a734e7..4750c09f2 100644 --- a/includes/Checker/Check_Result.php +++ b/includes/Checker/Check_Result.php @@ -90,6 +90,7 @@ public function plugin() { * @type string $file The file in which the message occurred. Default empty string (unknown file). * @type int $line The line on which the message occurred. Default 0 (unknown line). * @type int $column The column on which the message occurred. Default 0 (unknown column). + * @type string $link View in code editor link. Default empty string. * } */ public function add_message( $error, $message, $args = array() ) { @@ -98,6 +99,7 @@ public function add_message( $error, $message, $args = array() ) { 'file' => '', 'line' => 0, 'column' => 0, + 'link' => '', ); $data = array_merge( diff --git a/includes/Traits/Amend_Check_Result.php b/includes/Traits/Amend_Check_Result.php index a9e76311c..b13bb3c4a 100644 --- a/includes/Traits/Amend_Check_Result.php +++ b/includes/Traits/Amend_Check_Result.php @@ -16,6 +16,8 @@ */ trait Amend_Check_Result { + use File_Editor_URL; + /** * Amends the given result with a message for the specified file, including error information. * @@ -38,6 +40,7 @@ protected function add_result_message_for_file( Check_Result $result, $error, $m 'file' => str_replace( $result->plugin()->path(), '', $file ), 'line' => $line, 'column' => $column, + 'link' => $this->get_file_editor_url( $result, $file, $line ), ) ); } diff --git a/includes/Traits/File_Editor_URL.php b/includes/Traits/File_Editor_URL.php new file mode 100644 index 000000000..9eb412291 --- /dev/null +++ b/includes/Traits/File_Editor_URL.php @@ -0,0 +1,116 @@ +plugin()->path( '/' ); + $plugin_slug = basename( $plugin_path ); + $filename = str_replace( $plugin_path, '', $filename ); + /** + * Filters the template for the URL for linking to an external editor to open a file for editing. + * + * Users of IDEs that support opening files in via web protocols can use this filter to override + * the edit link to result in their editor opening rather than the plugin editor. + * + * The initial filtered value is null, requiring extension plugins to supply the URL template + * string themselves. If no template string is provided, links to the plugin editors will + * be provided if available. For example, for an extension plugin to cause file edit links to + * open in an IDE, the following filters can be used: + * + * # PhpStorm + * add_filter( 'wp_plugin_check_validation_error_source_file_editor_url_template', function () { + * return 'phpstorm://open?file={{file}}&line={{line}}'; + * } ); + * + * # VS Code + * add_filter( 'wp_plugin_check_validation_error_source_file_editor_url_template', function () { + * return 'vscode://file/{{file}}:{{line}}'; + * } ); + * + * For a template to be considered, the string '{{file}}' must be present in the filtered value. + * + * @since n.e.x.t + * + * @param string|null $editor_url_template Editor URL template. default null. + */ + $editor_url_template = apply_filters( 'wp_plugin_check_validation_error_source_file_editor_url_template', null ); + + // Supply the file path to the editor template. + if ( null !== $editor_url_template && str_contains( $editor_url_template, '{{file}}' ) ) { + $file_path = WP_PLUGIN_DIR . '/' . $plugin_slug; + if ( $plugin_slug !== $filename ) { + $file_path .= '/' . $filename; + } + + if ( file_exists( $file_path ) ) { + /** + * Filters the file path to be opened in an external editor for a given PHPCS error source. + * + * This is useful to map the file path from inside of a Docker container or VM to the host machine. + * + * @since n.e.x.t + * + * @param string|null $editor_url_template Editor URL template. + * @param array $source Source information. + */ + $file_path = apply_filters( 'plugin_check_validation_error_source_file_path', $file_path, array( $plugin_slug, $filename, $line ) ); + if ( $file_path ) { + $edit_url = str_replace( + array( + '{{file}}', + '{{line}}', + ), + array( + rawurlencode( $file_path ), + $line, + ), + $editor_url_template + ); + } + } + } + + // Fall back to using the plugin editor if no external editor is offered. + if ( ! $edit_url ) { + return add_query_arg( + array( + 'plugin' => rawurlencode( $result->plugin()->basename() ), + 'file' => rawurlencode( $plugin_slug . '/' . $filename ), + 'line' => $line, + ), + admin_url( 'plugin-editor.php' ) + ); + } + return $edit_url; + } +} diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1f85efe98..b8b9a4db3 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -20,3 +20,4 @@ parameters: paths: - includes/Checker/Checks/Abstract_File_Check.php - includes/Traits/Find_Readme.php + - includes/Traits/File_Editor_URL.php diff --git a/templates/results-row.php b/templates/results-row.php index 8a3b6d6b1..9969b0e01 100644 --- a/templates/results-row.php +++ b/templates/results-row.php @@ -14,5 +14,10 @@ {{data.message}} + + <# if ( data.link ) { #> + + <# } #> + diff --git a/templates/results-table.php b/templates/results-table.php index 7af4860af..5efac9225 100644 --- a/templates/results-table.php +++ b/templates/results-table.php @@ -17,6 +17,7 @@ + diff --git a/tests/phpunit/Checker/Check_Result_Tests.php b/tests/phpunit/Checker/Check_Result_Tests.php index a97369953..d97d7e093 100644 --- a/tests/phpunit/Checker/Check_Result_Tests.php +++ b/tests/phpunit/Checker/Check_Result_Tests.php @@ -59,6 +59,7 @@ public function test_add_message_with_warning() { $expected = array( 'message' => 'Warning message', 'code' => 'test_warning', + 'link' => '', ); $this->assertEquals( $expected, $warnings['test-plugin.php'][12][40][0] ); @@ -92,6 +93,7 @@ public function test_add_message_with_error() { $expected = array( 'message' => 'Error message', 'code' => 'test_error', + 'link' => '', ); $this->assertEquals( $expected, $errors['test-plugin.php'][22][30][0] ); @@ -122,6 +124,7 @@ public function test_get_errors_with_errors() { $expected = array( 'message' => 'Error message', 'code' => 'test_error', + 'link' => '', ); $this->assertEquals( $expected, $errors['test-plugin.php'][22][30][0] ); @@ -152,6 +155,7 @@ public function test_get_warnings_with_warnings() { $expected = array( 'message' => 'Warning message', 'code' => 'test_warning', + 'link' => '', ); $this->assertEquals( $expected, $warnings['test-plugin.php'][22][30][0] ); From f323f66f638430e109ec07c63545a27fba93dae7 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Mon, 23 Oct 2023 17:47:23 +0530 Subject: [PATCH 02/10] Remove title attribute --- templates/results-row.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/results-row.php b/templates/results-row.php index 9969b0e01..e0a7f9b29 100644 --- a/templates/results-row.php +++ b/templates/results-row.php @@ -16,7 +16,7 @@ <# if ( data.link ) { #> - + <# } #> From 4144838aef9945ab9dd33a0ecd209db22aade927 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Tue, 24 Oct 2023 10:46:16 +0530 Subject: [PATCH 03/10] Apply suggestions from code review Co-authored-by: Weston Ruter --- templates/results-row.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/results-row.php b/templates/results-row.php index e0a7f9b29..a541f1ab3 100644 --- a/templates/results-row.php +++ b/templates/results-row.php @@ -16,7 +16,7 @@ <# if ( data.link ) { #> - + <# } #> From 733479ba08131f263610689f37454f24c47f71e1 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Tue, 24 Oct 2023 11:44:34 +0530 Subject: [PATCH 04/10] Add editor file permission check and some adjustment --- includes/Traits/File_Editor_URL.php | 8 ++++++-- templates/results-row.php | 8 ++++---- templates/results-table.php | 3 +-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/includes/Traits/File_Editor_URL.php b/includes/Traits/File_Editor_URL.php index 9eb412291..dc1e48bc8 100644 --- a/includes/Traits/File_Editor_URL.php +++ b/includes/Traits/File_Editor_URL.php @@ -83,7 +83,7 @@ protected function get_file_editor_url( Check_Result $result, $filename, $line ) * @param string|null $editor_url_template Editor URL template. * @param array $source Source information. */ - $file_path = apply_filters( 'plugin_check_validation_error_source_file_path', $file_path, array( $plugin_slug, $filename, $line ) ); + $file_path = apply_filters( 'wp_plugin_check_validation_error_source_file_path', $file_path, array( $plugin_slug, $filename, $line ) ); if ( $file_path ) { $edit_url = str_replace( array( @@ -101,7 +101,11 @@ protected function get_file_editor_url( Check_Result $result, $filename, $line ) } // Fall back to using the plugin editor if no external editor is offered. - if ( ! $edit_url ) { + if ( + ! $edit_url + && ! ( defined( 'DISALLOW_FILE_EDIT' ) && true === DISALLOW_FILE_EDIT ) + && current_user_can( 'edit_plugins' ) + ) { return add_query_arg( array( 'plugin' => rawurlencode( $result->plugin()->basename() ), diff --git a/templates/results-row.php b/templates/results-row.php index a541f1ab3..cbdb0ff84 100644 --- a/templates/results-row.php +++ b/templates/results-row.php @@ -14,10 +14,10 @@ {{data.message}} - - <# if ( data.link ) { #> + <# if ( data.link ) { #> + - <# } #> - + + <# } #> diff --git a/templates/results-table.php b/templates/results-table.php index 5efac9225..5f069dadd 100644 --- a/templates/results-table.php +++ b/templates/results-table.php @@ -14,10 +14,9 @@ - + - From 7f9f6e91a0a1704d725243dc87c36d2a51167b9d Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Wed, 25 Oct 2023 10:46:03 +0530 Subject: [PATCH 05/10] Apply suggestions from code review Co-authored-by: Felix Arntz --- includes/Traits/File_Editor_URL.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/includes/Traits/File_Editor_URL.php b/includes/Traits/File_Editor_URL.php index dc1e48bc8..a673f1f7e 100644 --- a/includes/Traits/File_Editor_URL.php +++ b/includes/Traits/File_Editor_URL.php @@ -101,11 +101,7 @@ protected function get_file_editor_url( Check_Result $result, $filename, $line ) } // Fall back to using the plugin editor if no external editor is offered. - if ( - ! $edit_url - && ! ( defined( 'DISALLOW_FILE_EDIT' ) && true === DISALLOW_FILE_EDIT ) - && current_user_can( 'edit_plugins' ) - ) { + if ( ! $edit_url && current_user_can( 'edit_plugins' ) ) { return add_query_arg( array( 'plugin' => rawurlencode( $result->plugin()->basename() ), From 5df8da4698ccff1d0998f8435cbae17ee8a91435 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Thu, 26 Oct 2023 13:25:59 +0530 Subject: [PATCH 06/10] Update logic for edit link column --- assets/js/plugin-check-admin.js | 41 +++++++++++++++++++++++++++------ templates/results-row.php | 7 ++++-- templates/results-table.php | 7 +++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/assets/js/plugin-check-admin.js b/assets/js/plugin-check-admin.js index f2ae221f0..d864d38c3 100644 --- a/assets/js/plugin-check-admin.js +++ b/assets/js/plugin-check-admin.js @@ -355,30 +355,56 @@ Date.now().toString( 36 ) + Math.random().toString( 36 ).substr( 2 ); + // Check if any errors or warnings have links. + const hasLinks = + hasLinksInResults( errors ) || hasLinksInResults( warnings ); + // Render the file table. resultsContainer.innerHTML += renderTemplate( 'plugin-check-results-table', - { file, index } + { file, index, hasLinks } ); const resultsTable = document.getElementById( 'plugin-check__results-body-' + index ); // Render results to the table. - renderResultRows( 'ERROR', errors, resultsTable ); - renderResultRows( 'WARNING', warnings, resultsTable ); + renderResultRows( 'ERROR', errors, resultsTable, hasLinks ); + renderResultRows( 'WARNING', warnings, resultsTable, hasLinks ); } /** - * Renders a result row onto the file table. + * Checks if there are any links in the results object. * * @since n.e.x.t * - * @param {string} type The result type. Either ERROR or WARNING. * @param {Object} results The results object. - * @param {Object} table The HTML table to append a result row to. + * @return {boolean} True if there are links, false otherwise. + */ + function hasLinksInResults( results ) { + for ( const line in results ) { + for ( const column in results[ line ] ) { + for ( let i = 0; i < results[ line ][ column ].length; i++ ) { + if ( results[ line ][ column ][ i ].link ) { + return true; + } + } + } + } + return false; + } + + /** + * Renders a result row onto the file table. + * + * @since n.e.x.t + * + * @param {string} type The result type. Either ERROR or WARNING. + * @param {Object} results The results object. + * @param {Object} table The HTML table to append a result row to. + * @param {boolean} hasLinks Whether any result has links. */ - function renderResultRows( type, results, table ) { + function renderResultRows( type, results, table, hasLinks ) { // Loop over each result by the line, column and messages. for ( const line in results ) { for ( const column in results[ line ] ) { @@ -396,6 +422,7 @@ message, code, link, + hasLinks, } ); } diff --git a/templates/results-row.php b/templates/results-row.php index cbdb0ff84..e913046c3 100644 --- a/templates/results-row.php +++ b/templates/results-row.php @@ -14,9 +14,12 @@ {{data.message}} - <# if ( data.link ) { #> + <# if ( data.hasLinks ) { #> - + > + + + <# } #> diff --git a/templates/results-table.php b/templates/results-table.php index 5f069dadd..2c10949b2 100644 --- a/templates/results-table.php +++ b/templates/results-table.php @@ -14,9 +14,14 @@ - + + <# if ( data.hasLinks ) { #> + + + + <# } #> From b8fe450689bf553046912338c86d6d7bdbe0ab44 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Mon, 30 Oct 2023 10:14:56 +0530 Subject: [PATCH 07/10] Apply suggestions from code review Co-authored-by: Felix Arntz --- templates/results-row.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/results-row.php b/templates/results-row.php index e913046c3..71381c7e3 100644 --- a/templates/results-row.php +++ b/templates/results-row.php @@ -16,7 +16,7 @@ <# if ( data.hasLinks ) { #> - > + From 55d8780ec5afb884020e8f13d22002e50caf4c65 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Mon, 30 Oct 2023 10:23:36 +0530 Subject: [PATCH 08/10] Check link for row --- templates/results-row.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/templates/results-row.php b/templates/results-row.php index 71381c7e3..4d0733bcb 100644 --- a/templates/results-row.php +++ b/templates/results-row.php @@ -16,10 +16,12 @@ <# if ( data.hasLinks ) { #> - - - - + <# if ( data.link ) { #> + + + + + <# } #> <# } #> From c202309f11e25fff5e66ae3dad53e4b854b8a5f2 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Tue, 31 Oct 2023 11:15:38 +0530 Subject: [PATCH 09/10] Apply suggestions from Felix's code review Co-authored-by: Felix Arntz --- includes/Traits/File_Editor_URL.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/includes/Traits/File_Editor_URL.php b/includes/Traits/File_Editor_URL.php index a673f1f7e..42c5b6edd 100644 --- a/includes/Traits/File_Editor_URL.php +++ b/includes/Traits/File_Editor_URL.php @@ -23,13 +23,10 @@ trait File_Editor_URL { * * @param Check_Result $result The check result to amend, including the plugin context to check. * @param string $filename Error file name. - * @param int $line Line number of error. + * @param int $line Optional. Line number of error. Default 0 (no specific line). * @return string|null File editor URL or null if not available. */ - protected function get_file_editor_url( Check_Result $result, $filename, $line ) { - if ( ! isset( $filename, $line ) ) { - return null; - } + protected function get_file_editor_url( Check_Result $result, $filename, $line = 0 ) { $edit_url = null; @@ -102,12 +99,15 @@ protected function get_file_editor_url( Check_Result $result, $filename, $line ) // Fall back to using the plugin editor if no external editor is offered. if ( ! $edit_url && current_user_can( 'edit_plugins' ) ) { + $query_args = array( + 'plugin' => rawurlencode( $result->plugin()->basename() ), + 'file' => rawurlencode( $plugin_slug . '/' . $filename ), + ); + if ( $line ) { + $query_args['line'] = $line; + } return add_query_arg( - array( - 'plugin' => rawurlencode( $result->plugin()->basename() ), - 'file' => rawurlencode( $plugin_slug . '/' . $filename ), - 'line' => $line, - ), + $query_args, admin_url( 'plugin-editor.php' ) ); } From 0ef24763e1fde59359c84e1789b54bd2fcba7c50 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Tue, 31 Oct 2023 11:20:53 +0530 Subject: [PATCH 10/10] Apply suggestions from code review Co-authored-by: Weston Ruter --- includes/Traits/File_Editor_URL.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Traits/File_Editor_URL.php b/includes/Traits/File_Editor_URL.php index 42c5b6edd..758adadd8 100644 --- a/includes/Traits/File_Editor_URL.php +++ b/includes/Traits/File_Editor_URL.php @@ -63,7 +63,7 @@ protected function get_file_editor_url( Check_Result $result, $filename, $line = $editor_url_template = apply_filters( 'wp_plugin_check_validation_error_source_file_editor_url_template', null ); // Supply the file path to the editor template. - if ( null !== $editor_url_template && str_contains( $editor_url_template, '{{file}}' ) ) { + if ( is_string( $editor_url_template ) && str_contains( $editor_url_template, '{{file}}' ) ) { $file_path = WP_PLUGIN_DIR . '/' . $plugin_slug; if ( $plugin_slug !== $filename ) { $file_path .= '/' . $filename;