diff --git a/assets/js/plugin-check-admin.js b/assets/js/plugin-check-admin.js
index e75220958..9e79555ff 100644
--- a/assets/js/plugin-check-admin.js
+++ b/assets/js/plugin-check-admin.js
@@ -38,6 +38,9 @@
'plugin-check__include-experimental'
);
const useAi = document.getElementById( 'plugin-check__use-ai' );
+ const usePcpignore = document.getElementById(
+ 'plugin-check__use-pcpignore'
+ );
// Handle disabling the Check it button when a plugin is not selected.
function canRunChecks() {
@@ -141,6 +144,9 @@
if ( useAi ) {
useAi.disabled = true;
}
+ if ( usePcpignore ) {
+ usePcpignore.disabled = true;
+ }
if ( includeExperimental ) {
includeExperimental.disabled = true;
}
@@ -149,6 +155,8 @@
const categories = getSelectedValues( categoriesList );
const types = getSelectedValues( typesList );
const useAiChecked = useAi && useAi.checked ? 1 : 0;
+ const usePcpignoreChecked =
+ usePcpignore && usePcpignore.checked ? 1 : 0;
const includeExperimentalChecked =
includeExperimental && includeExperimental.checked ? 1 : 0;
let currentChecks;
@@ -157,7 +165,8 @@
plugin,
categories,
includeExperimentalChecked,
- useAiChecked
+ useAiChecked,
+ usePcpignoreChecked
)
.then( ( data ) => {
currentChecks = data.checks;
@@ -165,7 +174,8 @@
plugin,
currentChecks,
includeExperimentalChecked,
- useAiChecked
+ useAiChecked,
+ usePcpignoreChecked
);
} )
.then( () =>
@@ -174,7 +184,8 @@
currentChecks,
types,
includeExperimentalChecked,
- useAiChecked
+ useAiChecked,
+ usePcpignoreChecked
)
)
.then( () => cleanUpEnvironment() )
@@ -224,6 +235,9 @@
if ( useAi ) {
useAi.disabled = false;
}
+ if ( usePcpignore ) {
+ usePcpignore.disabled = false;
+ }
if ( includeExperimental ) {
includeExperimental.disabled = false;
}
@@ -639,13 +653,15 @@
* @param {Array} checks Check slugs that will run.
* @param {number} includeExperimentalInput Whether to include experimental checks.
* @param {number} useAiInput Whether to enable AI analysis.
+ * @param {number} usePcpignoreInput Whether to apply .pcpignore exclusions.
* @return {Promise
+
diff --git a/tests/behat/features/plugin-check.feature b/tests/behat/features/plugin-check.feature
index 903b132bc..6d7dcbf9a 100644
--- a/tests/behat/features/plugin-check.feature
+++ b/tests/behat/features/plugin-check.feature
@@ -314,6 +314,143 @@ Feature: Test that the WP-CLI command works.
FILE: subdirectory/error.php
"""
+ Scenario: Apply .pcpignore exclusions only when requested
+ Given a WP install with the Plugin Check plugin
+ And an empty wp-content/plugins/foo-plugin directory
+ And an empty wp-content/plugins/foo-plugin/docs directory
+ And a wp-content/plugins/foo-plugin/foo-plugin.php file:
+ """
+ assertEquals( $custom_ignore_files, $result );
}
+ public function test_get_pcpignore_exclusions() {
+ $plugin_directory = UNIT_TESTS_PLUGIN_DIR . 'test-plugin-pcpignore';
+
+ $exclusions = PCP_Ignore_Utility::get_exclusions( $plugin_directory );
+
+ $this->assertSame(
+ array( '/docs', '/tests/fixtures' ),
+ $exclusions['directories']
+ );
+ $this->assertSame(
+ array( '/development-only.php', '/*.map', '/.pcpignore' ),
+ $exclusions['files']
+ );
+ $this->assertSame( '', PCP_Ignore_Utility::get_warning() );
+ }
+
+ public function test_get_pcpignore_exclusions_without_ignore_file() {
+ $plugin_directory = UNIT_TESTS_PLUGIN_DIR . 'test-plugin-ignore-files';
+
+ $exclusions = PCP_Ignore_Utility::get_exclusions( $plugin_directory );
+
+ $this->assertSame(
+ array(
+ 'directories' => array(),
+ 'files' => array(),
+ ),
+ $exclusions
+ );
+ $this->assertSame( '', PCP_Ignore_Utility::get_warning() );
+ }
+
+ public function test_get_pcpignore_exclusions_for_single_file_plugin() {
+ $exclusions = PCP_Ignore_Utility::get_exclusions( WP_PLUGIN_DIR . '/foo-single.php' );
+
+ $this->assertSame(
+ array(
+ 'directories' => array(),
+ 'files' => array(),
+ ),
+ $exclusions
+ );
+ $this->assertSame( '', PCP_Ignore_Utility::get_warning() );
+ }
+
+ public function test_get_pcpignore_exclusions_with_unreadable_file() {
+ $plugin_directory = UNIT_TESTS_PLUGIN_DIR . 'test-plugin-pcpignore';
+ $ignore_file = trailingslashit( $plugin_directory ) . '.pcpignore';
+
+ chmod( $ignore_file, 0000 );
+ $this->cleanups[] = function () use ( $ignore_file ) {
+ chmod( $ignore_file, 0644 );
+ };
+
+ $exclusions = PCP_Ignore_Utility::get_exclusions( $plugin_directory );
+
+ $this->assertSame(
+ array(
+ 'directories' => array(),
+ 'files' => array(),
+ ),
+ $exclusions
+ );
+ $this->assertNotSame( '', PCP_Ignore_Utility::get_warning() );
+ }
+
+ public function test_pcpignore_directory_exclusion_is_anchored_to_plugin_root() {
+ $checks_to_run = array(
+ new I18n_Usage_Check(),
+ );
+
+ add_filter(
+ 'wp_plugin_check_checks',
+ function () {
+ return array(
+ 'i18n_usage_check' => new I18n_Usage_Check(),
+ );
+ }
+ );
+
+ // Without exclusions, both docs/example.php (root) and
+ // includes/docs/real-code.php (nested) trigger a warning.
+ $check_context = new Check_Context( UNIT_TESTS_PLUGIN_DIR . 'test-plugin-pcpignore/load.php' );
+ $results_without = ( new Checks() )->run_checks( $check_context, $checks_to_run );
+
+ $this->assertSame( 2, $results_without->get_warning_count() );
+
+ // With .pcpignore exclusions applied, only the root-level docs/
+ // directory is excluded; the nested includes/docs/ directory, which
+ // merely shares the same directory name, must still be scanned.
+ PCP_Ignore_Utility::apply_exclusions( UNIT_TESTS_PLUGIN_DIR . 'test-plugin-pcpignore' );
+
+ $check_context = new Check_Context( UNIT_TESTS_PLUGIN_DIR . 'test-plugin-pcpignore/load.php' );
+ $results_with = ( new Checks() )->run_checks( $check_context, $checks_to_run );
+
+ $this->assertSame( 1, $results_with->get_warning_count() );
+ }
+
public function test_plugin_without_error_for_ignore_directories() {
$check_context = new Check_Context( UNIT_TESTS_PLUGIN_DIR . 'test-plugin-ignore-directories/load.php' );