<?xml version="1.0"?>
<ruleset name="BreadButter WordPress Plugin">
    <description>PHPCS ruleset for the Bread &amp; Butter WordPress plugin. Emphasis on WordPress security sniffs — the escaping / sanitization / SQL-prep rules that stop regressions like the customEventShortCodeButton XSS (CVE-2026-4279). Stylistic rules (class/file naming, doc-comment requirements) are excluded because this codebase uses PSR-4 + camelCase, not WP core naming.</description>

    <!-- Directories to scan -->
    <file>./src</file>
    <file>./breadbutter-connect.php</file>
    <file>./uninstall.php</file>
    <file>./index.php</file>

    <!-- Third-party / generated / built assets -->
    <exclude-pattern>*/vendor/*</exclude-pattern>
    <exclude-pattern>*/node_modules/*</exclude-pattern>
    <exclude-pattern>*/build/*</exclude-pattern>
    <exclude-pattern>*/assets/*</exclude-pattern>
    <exclude-pattern>*/blocks/*/build/*</exclude-pattern>
    <exclude-pattern>*/bitbucket-pipeline-scripts/*</exclude-pattern>

    <!-- Show sniff codes in output, enable colours, scan only .php, parallelise. -->
    <arg value="sp"/>
    <arg name="colors"/>
    <arg name="extensions" value="php"/>
    <arg name="parallel" value="8"/>

    <!-- Core ruleset: WordPress-Extra pulls in security + best-practice sniffs. -->
    <rule ref="WordPress-Extra">
        <!-- Stylistic: this codebase uses PSR-4 and camelCase, not WP core naming -->
        <exclude name="WordPress.Files.FileName"/>
        <exclude name="WordPress.NamingConventions.ValidVariableName"/>
        <exclude name="WordPress.NamingConventions.ValidFunctionName"/>
        <exclude name="WordPress.NamingConventions.ValidHookName"/>
        <exclude name="WordPress.NamingConventions.PrefixAllGlobals"/>

        <!-- Doc-comment sniffs: not enforced in this codebase; too noisy to retrofit -->
        <exclude name="Generic.Commenting.DocComment"/>
        <exclude name="Squiz.Commenting"/>
        <exclude name="Generic.Commenting.Todo"/>

        <!-- I18n: plugin has a text domain but hasn't been fully translated; don't block on this -->
        <exclude name="WordPress.WP.I18n"/>

        <!-- Whitespace sniffs are style-only and produce lots of noise on existing files -->
        <exclude name="WordPress.WhiteSpace.ControlStructureSpacing"/>
        <exclude name="WordPress.WhiteSpace.OperatorSpacing"/>
        <exclude name="WordPress.Arrays.ArrayIndentation"/>
        <exclude name="WordPress.Arrays.ArrayKeySpacingRestrictions"/>
        <exclude name="WordPress.Arrays.MultipleStatementAlignment"/>
        <exclude name="Generic.WhiteSpace"/>
        <exclude name="Squiz.WhiteSpace"/>
        <exclude name="PEAR.Functions.FunctionCallSignature"/>

        <!-- Yoda conditions: style preference, not a correctness / security sniff. Modern
             PHP ecosystems have largely moved past it. Excluding across the whole project
             rather than retrofitting 60+ call sites. -->
        <exclude name="WordPress.PHP.YodaConditions"/>

        <!-- 'This comment is XX% valid code; is this commented out code?' is a heuristic
             warning and fires on every HTML-in-a-comment template or example in docblock.
             Too noisy to leave on; real commented-out code is better caught at review time. -->
        <exclude name="Squiz.PHP.CommentedOutCode"/>

        <!-- StrictInArray is a stylistic preference (third arg to in_array); the code
             paths that hit it deal with string-only arrays so type juggling isn't an issue.
             Defer to a targeted refactor ticket if we want to enforce this later. -->
        <exclude name="WordPress.PHP.StrictInArray"/>
    </rule>

    <!-- Security sniffs: always enforce (this is the reason we're doing this at all).
         Two legacy files (Ajax.php, LoginAuthorize.php) and one callbacks directory have
         NonceVerification / ValidatedSanitizedInput debt that predates this workflow and
         requires a per-handler security audit to fix properly (adding nonce checks can
         change behaviour). Excluded from those two sniff families only, so:
           - new files / new code in those files still enforce the sniffs
           - all OTHER sniffs in WordPress.Security (EscapeOutput, SafeRedirect, etc.) are
             still enforced on those files
           - all sniffs are enforced on every other file in the codebase
         TODO: audit ticket — add nonce / unslash / sanitize on each $_GET/$_POST site and
         remove these excludes. Tracking in WPP-443 follow-ups. -->
    <rule ref="WordPress.Security"/>
    <rule ref="WordPress.Security.NonceVerification">
        <exclude-pattern>src/Base/Ajax\.php</exclude-pattern>
        <exclude-pattern>src/Pages/LoginAuthorize\.php</exclude-pattern>
        <exclude-pattern>src/Api/Callbacks/AdminCallbacks\.php</exclude-pattern>
    </rule>
    <rule ref="WordPress.Security.ValidatedSanitizedInput">
        <exclude-pattern>src/Base/Ajax\.php</exclude-pattern>
        <exclude-pattern>src/Pages/LoginAuthorize\.php</exclude-pattern>
        <exclude-pattern>src/Api/Callbacks/AdminCallbacks\.php</exclude-pattern>
    </rule>

    <!-- Plugin text domain (used by WP.WP.I18n when enabled downstream) -->
    <config name="text_domain" value="breadbutter-connect,default"/>

    <!-- Minimum supported WP and PHP versions — adjust when README.txt "Requires at least" changes -->
    <config name="minimum_supported_wp_version" value="6.0"/>
    <config name="testVersion" value="7.4-"/>
</ruleset>
