<?xml version="1.0"?>
<ruleset name="Custom Guest Authors">

	<description>PHPCS configuration for the Custom Guest Authors plugin.</description>

	<!-- Scan all PHP files in the plugin directory -->
	<file>.</file>

	<!-- Exclude non-PHP directories -->
	<exclude-pattern>*/languages/*</exclude-pattern>
	<exclude-pattern>*/node_modules/*</exclude-pattern>
	<exclude-pattern>*/vendor/*</exclude-pattern>

	<!-- Enforce the full WordPress Coding Standards ruleset -->
	<rule ref="WordPress"/>

	<!--
		── Prefix whitelist ────────────────────────────────────────────────────
		Declare the authorised function/class/constant prefixes for this plugin.
		Without this every cga_* and custom_guest_authors_* name triggers a
		PrefixAllGlobals false positive.
	-->
	<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
		<properties>
			<property name="prefixes" type="array">
				<element value="cga"/>
				<element value="custom_guest_authors"/>
				<element value="CGA"/>
			</property>
		</properties>
	</rule>

	<!--
		── $_GET reads without nonce verification ───────────────────────────────
		The plugin reads several $_GET parameters for read-only UI state:
		  - tab, page, settings-updated  (settings page tab routing — WordPress
		    core itself passes these; no user-controlled content is acted on)
		  - cga_test_id                  (debug tab manual post tester — absint()
		    sanitised, no data is written)
		  - cga_action + _wpnonce        (clear-cache action — wp_verify_nonce()
		    IS called; PHPCS cannot see the conditional nonce check and fires
		    NonceVerification.Recommended on every $_GET access in the block)

		All destructive actions are nonce-gated. Suppressing the recommendation
		here is intentional and safe for these specific read-only contexts.
	-->
	<rule ref="WordPress.Security.NonceVerification.Recommended">
		<exclude-pattern>*/admin/views/settings-page.php</exclude-pattern>
		<exclude-pattern>*/admin/views/tab-debug.php</exclude-pattern>
	</rule>

	<!--
		── Direct database queries ──────────────────────────────────────────────
		Four legitimate direct $wpdb queries exist in this plugin:

		1. includes/cache.php — version-based transient flush on plugin update.
		   Uses LIKE '_transient_cga_%'. There is no WordPress API equivalent
		   for bulk-deleting transients by prefix; $wpdb->query() is the only
		   option. Caching the result of a DELETE is not applicable.

		2. admin/views/settings-page.php — Clear Cache button handler.
		   Same operation, same justification as includes/cache.php.

		3. admin/views/tab-debug.php — transient count query for the Debug tab.
		   A SELECT COUNT(*) with a LIKE prefix has no WP API equivalent.
		   Result is immediately stored in wp_cache_set() after retrieval.

		4. uninstall.php — bulk deletion of all cga_ transients on plugin removal.
		   Same justification as includes/cache.php; no WP API equivalent.
	-->
	<rule ref="WordPress.DB.DirectDatabaseQuery.DirectQuery">
		<exclude-pattern>*/includes/cache.php</exclude-pattern>
		<exclude-pattern>*/admin/views/settings-page.php</exclude-pattern>
		<exclude-pattern>*/admin/views/tab-debug.php</exclude-pattern>
		<exclude-pattern>*/uninstall.php</exclude-pattern>
	</rule>
	<rule ref="WordPress.DB.DirectDatabaseQuery.NoCaching">
		<exclude-pattern>*/includes/cache.php</exclude-pattern>
		<exclude-pattern>*/admin/views/settings-page.php</exclude-pattern>
		<exclude-pattern>*/uninstall.php</exclude-pattern>
	</rule>

	<!--
		── Variable naming in view templates ───────────────────────────────────
		admin/views/settings-page.php and admin/views/tab-debug.php are loaded
		via require_once from inside cga_render_settings_page(), so all variables
		in those files exist in function scope, not global scope. PHPCS/Plugin
		Check cannot see the require_once call-site and incorrectly treats them
		as global. The exclusion is intentional: no user-controlled values reach
		the global namespace from these files.

		Note: Plugin Check does not honour phpcs.xml exclude-patterns for this
		rule. Both view files carry inline phpcs:disable / phpcs:enable fences
		as the Plugin Check fallback; this file-level exclusion applies for local
		PHPCS runs only.
	-->
	<rule ref="WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound">
		<exclude-pattern>*/admin/views/*</exclude-pattern>
	</rule>

	<!--
		── PHP version compatibility ────────────────────────────────────────────
		Aligns with `Requires PHP: 8.2` in readme.txt.
	-->
	<config name="testVersion" value="8.2-"/>

	<!--
		── WordPress version compatibility ─────────────────────────────────────
		Aligns with `Requires at least: 5.7` in readme.txt.
	-->
	<config name="minimum_wp_version" value="5.7"/>

</ruleset>
