Skip to content

Commit

Permalink
Merge pull request #298 from WordPress/fix/251-add-plugin-editor-link
Browse files Browse the repository at this point in the history
Add link to Plugin Editor for each found issue to jump user to file and line of code
  • Loading branch information
mukeshpanchal27 authored Nov 1, 2023
2 parents cc65fc1 + e9b5927 commit 74bc890
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 7 deletions.
43 changes: 36 additions & 7 deletions assets/js/plugin-check-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,36 +378,63 @@
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 ] ) {
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',
Expand All @@ -417,6 +444,8 @@
type,
message,
code,
link,
hasLinks,
}
);
}
Expand Down
36 changes: 36 additions & 0 deletions includes/Admin/Admin_Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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.
*
Expand Down
2 changes: 2 additions & 0 deletions includes/Checker/Check_Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -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() ) {
Expand All @@ -98,6 +99,7 @@ public function add_message( $error, $message, $args = array() ) {
'file' => '',
'line' => 0,
'column' => 0,
'link' => '',
);

$data = array_merge(
Expand Down
3 changes: 3 additions & 0 deletions includes/Traits/Amend_Check_Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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 ),
)
);
}
Expand Down
116 changes: 116 additions & 0 deletions includes/Traits/File_Editor_URL.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php
/**
* Trait WordPress\Plugin_Check\Traits\File_Editor_URL
*
* @package plugin-check
*/

namespace WordPress\Plugin_Check\Traits;

use WordPress\Plugin_Check\Checker\Check_Result;

/**
* Trait for file editor URL.
*
* @since n.e.x.t
*/
trait File_Editor_URL {

/**
* Gets the URL for opening the plugin file in an external editor.
*
* @since n.e.x.t
*
* @param Check_Result $result The check result to amend, including the plugin context to check.
* @param string $filename Error file name.
* @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 = 0 ) {

$edit_url = null;

$plugin_path = $result->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 ( 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;
}

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( 'wp_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 && 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(
$query_args,
admin_url( 'plugin-editor.php' )
);
}
return $edit_url;
}
}
1 change: 1 addition & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ parameters:
paths:
- includes/Checker/Checks/Abstract_File_Check.php
- includes/Traits/Find_Readme.php
- includes/Traits/File_Editor_URL.php
10 changes: 10 additions & 0 deletions templates/results-row.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,15 @@
<td>
{{data.message}}
</td>
<# if ( data.hasLinks ) { #>
<td>
<# if ( data.link ) { #>
<a href="{{data.link}}" target="_blank">
<?php esc_html_e( 'View in code editor', 'plugin-check' ); ?>
<span class="screen-reader-text"><?php esc_html_e( '(opens in a new tab)', 'plugin-check' ); ?></span>
</a>
<# } #>
</td>
<# } #>
</tr>

5 changes: 5 additions & 0 deletions templates/results-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<td>
<?php esc_html_e( 'Message', 'plugin-check' ); ?>
</td>
<# if ( data.hasLinks ) { #>
<td>
<?php esc_html_e( 'Edit Link', 'plugin-check' ); ?>
</td>
<# } #>
</tr>
</thead>
<tbody id="plugin-check__results-body-{{data.index}}"></tbody>
Expand Down
4 changes: 4 additions & 0 deletions tests/phpunit/Checker/Check_Result_Tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -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] );
Expand Down Expand Up @@ -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] );
Expand Down Expand Up @@ -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] );
Expand Down Expand Up @@ -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] );
Expand Down

0 comments on commit 74bc890

Please sign in to comment.