# agent.md

This file defines **mandatory rules** for all code contributions to the Modern Cart for WooCommerce plugin repository. These rules are **strictly enforced** and **non-negotiable**. All contributors—human and AI—must comply 100%.

This file **extends** and **enforces** the guidance in `CLAUDE.md`. Where conflicts arise, this file takes precedence for code authoring rules.

---

## 1. Plugin Identity & Scope

### Plugin Definition
- **Name**: Modern Cart Starter for WooCommerce
- **Type**: Free WordPress plugin
- **Purpose**: Enhance WooCommerce shopping cart with modern slide-out/popup cart functionality
- **Text Domain**: `modern-cart` (NEVER use any other text domain)
- **Namespace**: `ModernCart` (NEVER use global namespace for plugin classes)
- **Version**: Defined in `MODERNCART_VER` constant in `modern-cart.php`

### Relationship to Pro Plugin
- Pro version exists at `/modern-cart-woo/` (separate repository)
- Free and Pro can coexist on the same WordPress installation
- Free plugin MUST check Pro version compatibility in `moderncart_is_safe_to_init()`
- Pro must be >= 1.2.0 for compatibility
- NEVER implement Pro features in the free plugin
- NEVER duplicate code between free and Pro—coordinate shared logic

### Supported Environment
- **WordPress**: 5.4+ minimum, tested up to 6.9
- **WooCommerce**: 3.0+ minimum, tested up to 9.8.4
- **PHP**: 7.4+ minimum
- **Dependencies**: WooCommerce MUST be active for plugin to load classes

### Scope Boundaries
**This repository IS responsible for:**
- Side cart (slide-out) functionality
- Popup cart (floating) functionality
- Basic cart rendering and AJAX operations
- Admin settings dashboard (React-based)
- Frontend asset enqueueing
- WooCommerce cart integration
- Compatibility declarations (HPOS)

**This repository is NOT responsible for:**
- Premium features (upsells, cross-sells, A/B testing)
- Payment gateway modifications
- WooCommerce core checkout process (only enhances cart step)
- Third-party plugin conflicts (unless explicitly documented)
- Multi-site activation (single-site focus)

---

## 2. Authoritative Architecture Rules

### Folder Responsibilities

#### `inc/`
- **Purpose**: Core PHP business logic
- **Allowed**: Singleton classes with `Get_Instance` trait, WooCommerce/WordPress integration, AJAX handlers, helper functions
- **Forbidden**: Direct HTML output (use templates), frontend asset files, React components, admin page rendering (use `admin-core/`)

#### `inc/traits/`
- **Purpose**: Reusable PHP traits
- **Current contents**: `get-instance.php` (singleton pattern)
- **Allowed**: Only traits used by 3+ classes
- **Forbidden**: Single-use traits, abstract classes (use traits or inheritance), business logic specific to one module

#### `admin-core/`
- **Purpose**: WordPress admin interface and React dashboard
- **Allowed**: Admin menu registration, React components, settings page logic
- **Forbidden**: Frontend logic, AJAX handlers for frontend operations, template rendering for frontend

#### `admin-core/assets/src/`
- **Purpose**: React source files for admin dashboard
- **Allowed**: React 18 components, JSX, SCSS, React Router, Context API
- **Forbidden**: jQuery, inline styles (use SCSS), direct DOM manipulation, global variables (except `moderncart_settings`)

#### `admin-core/assets/build/`
- **Purpose**: Webpack build output
- **Allowed**: Committed build artifacts (settings.js, settings.css)
- **Forbidden**: Manual edits (always regenerate with `npm run build`)

#### `assets/`
- **Purpose**: Frontend CSS and JavaScript
- **Subdirectories**:
  - `css/` - Source CSS files
  - `js/` - Source JavaScript files
  - `min-css/` - Minified CSS (generated by Grunt, never edit manually)
  - `min-js/` - Minified JavaScript (generated by Grunt, never edit manually)
- **Allowed**: Vanilla JavaScript, jQuery (WooCommerce compatibility), PostCSS
- **Forbidden**: React in frontend, inline styles, ES6+ without transpilation, direct edits to `min-*` folders

#### `templates/`
- **Purpose**: PHP template files for rendering HTML
- **Subdirectories**:
  - `cart/` - Slide-out and popup cart templates
  - `shop/` - Shop page templates
- **Allowed**: PHP, WooCommerce template structure, escaping functions, action/filter hooks
- **Forbidden**: Business logic (use `inc/` classes), direct database queries, unsanitized output

#### `vendor/`
- **Purpose**: Composer dependencies
- **Rule**: NEVER edit manually, NEVER commit changes except via `composer install/update`

#### `node_modules/`
- **Rule**: NEVER commit, NEVER edit

### Class Responsibility Boundaries

#### Single Responsibility Principle (MANDATORY)
- Each class MUST have ONE clear responsibility
- If a class name requires "and" or "or", it violates SRP
- Maximum 500 lines per class (excluding comments)
- Maximum 10 public methods per class

#### Current Class Responsibilities (DO NOT VIOLATE)

**`Plugin_Loader`** (`plugin-loader.php`)
- Autoloading classes
- Plugin activation/deactivation hooks
- Onboarding redirect logic
- Class instantiation order
- **NEVER**: Business logic, settings management, rendering

**`Helper`** (`inc/helper.php`)
- Settings defaults (`get_defaults()`)
- Settings retrieval with fallbacks
- Utility functions (array manipulation, string formatting)
- **NEVER**: AJAX handling, direct database writes, rendering

**`Scripts`** (`inc/scripts.php`)
- Asset enqueueing (CSS/JS)
- Localization script registration
- Asset dependency management
- **NEVER**: Asset generation, AJAX handling, settings storage

**`Slide_Out`** (`inc/slide-out.php`)
- Side cart rendering logic
- Side cart template loading
- Side cart visibility rules
- **NEVER**: AJAX processing (use `Slide_Out_Ajax`), popup cart logic, settings storage

**`Slide_Out_Ajax`** (`inc/slide-out-ajax.php`)
- Side cart AJAX endpoints
- Nonce verification for side cart
- WooCommerce session management for side cart
- **NEVER**: Rendering templates, direct HTML output, popup cart AJAX

**`Floating`** (`inc/floating.php`)
- Popup cart rendering logic
- Popup cart template loading
- Popup cart visibility rules
- **NEVER**: AJAX processing (use `Floating_Ajax`), side cart logic, settings storage

**`Floating_Ajax`** (`inc/floating-ajax.php`)
- Popup cart AJAX endpoints
- Nonce verification for popup cart
- WooCommerce session management for popup cart
- **NEVER**: Rendering templates, direct HTML output, side cart AJAX

**`Cart`** (`inc/cart.php`)
- Shared cart rendering logic
- Cart item display
- Cart totals calculation
- **NEVER**: AJAX handling, type-specific logic (delegate to `Slide_Out` or `Floating`)

**`Admin_Menu`** (`admin-core/admin-menu.php`)
- Admin menu registration
- Settings page registration
- Enqueuing React admin assets
- **NEVER**: Settings validation logic (use REST API or AJAX handlers), frontend logic

### When to Create a New Class vs Extend Existing

#### Create a New Class When:
- Introducing a new cart type (e.g., Mini Cart, Quick View)
- Adding a new AJAX endpoint group (3+ related endpoints)
- Implementing a new integration (e.g., payment gateway, page builder)
- Adding a new admin section with distinct UI

#### Extend Existing Class When:
- Adding a single method to existing responsibility
- Enhancing existing functionality without changing behavior
- Adding a helper function related to existing helpers

#### NEVER:
- Create utility classes with only static methods (use `Helper` or traits)
- Create "Manager" or "Controller" classes without specific responsibility
- Duplicate code across classes—extract to `Helper` or trait

### Strict Separation of Concerns

#### Logic Layer (`inc/` classes)
- Business rules
- Data retrieval and transformation
- Validation
- Permission checks
- **Output**: Structured data (arrays, objects)

#### Rendering Layer (`templates/` files)
- HTML structure
- CSS class application
- Escaping output
- **Input**: Structured data from logic layer
- **NEVER**: Database queries, complex calculations, business logic

#### Data Layer (WordPress/WooCommerce APIs)
- Settings storage (`get_option`, `update_option`)
- WooCommerce cart (`WC()->cart`)
- WooCommerce session (`WC()->session`)
- **Access**: Only through logic layer classes, NEVER directly in templates

---

## 3. File & Naming Conventions (STRICT)

### PHP Class Files

#### Class Names
- **Format**: PascalCase
- **Namespace**: `ModernCart` or `ModernCart\Inc` or `ModernCart\Admin_Core`
- **Examples**: `Plugin_Loader`, `Slide_Out_Ajax`, `Admin_Menu`
- **Rule**: Underscores for word separation in class names (WordPress convention)

#### File Names
- **Format**: kebab-case
- **Pattern**: `class-{class-name}.php` OR `{class-name}.php`
- **Examples**: `plugin-loader.php`, `slide-out.php`, `helper.php`
- **Rule**: Class name converted to lowercase with hyphens
- **Mapping**: `Slide_Out_Ajax` → `slide-out-ajax.php`

#### Trait Files
- **Format**: kebab-case
- **Pattern**: `{trait-name}.php` (no "trait-" prefix)
- **Example**: `get-instance.php`

#### Function Files
- **Format**: kebab-case
- **Example**: `functions.php`
- **Rule**: Only for global helper functions (avoid when possible)

### JavaScript Files

#### Admin React Files
- **Format**: PascalCase for components, kebab-case for utilities
- **Examples**: `Settings.js`, `ViewContainer.js`, `Onboarding.js`
- **Directory**: `admin-core/assets/src/`

#### Frontend JavaScript
- **Format**: kebab-case
- **Examples**: `slide-out.js`, `floating-cart.js`
- **Directory**: `assets/js/`
- **Minified**: `assets/min-js/{name}.min.js`

### CSS Files

#### Source Files
- **Format**: kebab-case
- **Examples**: `slide-out.css`, `floating-cart.css`, `admin-settings.css`
- **Directory**: `assets/css/` or `admin-core/assets/src/` (for SCSS)

#### Minified Files
- **Directory**: `assets/min-css/`
- **Format**: `{name}.min.css`, `{name}.min-rtl.css`
- **Rule**: NEVER edit minified files directly

### Constants

#### Format
- **Pattern**: `MODERNCART_{PURPOSE}`
- **Case**: SCREAMING_SNAKE_CASE
- **Prefix**: ALWAYS `MODERNCART_`

#### Existing Constants (DO NOT RENAME)
```php
MODERNCART_FILE
MODERNCART_DIR
MODERNCART_URL
MODERNCART_VER
MODERNCART_MAIN_SETTINGS
MODERNCART_SETTINGS
MODERNCART_FLOATING_SETTINGS
MODERNCART_APPEARANCE_SETTINGS
CARTFLOWS_DOMAIN_URL
MODERNCART_DEBUG
```

#### New Constants
- MUST be defined in `modern-cart.php` ONLY
- MUST be documented with PHPDoc comment
- MUST be prefixed with `MODERNCART_`
- Examples: `MODERNCART_CACHE_KEY`, `MODERNCART_API_VERSION`

### Hooks (Actions & Filters)

#### Action Names
- **Format**: `moderncart_{context}_{action}`
- **Examples**: `moderncart_before_slide_out`, `moderncart_cart_item_removed`
- **Rule**: Present tense for actions, past tense NOT allowed

#### Filter Names
- **Format**: `moderncart_{context}_{property}`
- **Examples**: `moderncart_slide_out_enabled`, `moderncart_cart_items`
- **Rule**: Describe what is being filtered, not the action

### Option Keys

#### Existing Options (DO NOT RENAME)
- `moderncart_main_settings`
- `moderncart_settings`
- `moderncart_floating_settings`
- `moderncart_appearance_settings`
- `moderncart_is_onboarding_complete`

#### New Options
- **Format**: `moderncart_{purpose}`
- **Rule**: Singular noun, lowercase, underscores
- **Example**: `moderncart_cache_version`

### Transients

#### Format
- **Pattern**: `moderncart_{purpose}_{scope}`
- **Example**: `moderncart_redirect_to_onboarding`
- **Expiration**: ALWAYS set expiration (NEVER permanent transients)

### AJAX Action Names

#### Format
- **Pattern**: `moderncart_{cart_type}_{operation}`
- **Examples**: `moderncart_slide_out_add_to_cart`, `moderncart_floating_update_quantity`
- **Rule**: Cart type prefix required (slide_out, floating)

### React Component Names

#### Format
- **Pattern**: PascalCase
- **Examples**: `ViewContainer`, `Onboarding`, `SettingsPanel`
- **File Name**: Same as component name (e.g., `ViewContainer.js`)

---

## 4. Coding Standards (ENFORCED)

### PHP Standards

#### PHPCS Rules
- **Rulesets**: WordPress-Core, WordPress-Extra, WordPress-VIP-Go
- **Config**: `phpcs.xml.dist`
- **Command**: `composer lint`
- **Fix Command**: `composer format`
- **Pre-commit**: MUST run `composer format` before committing PHP
- **Zero Tolerance**: NO PHPCS errors allowed in committed code

#### PHPStan Rules
- **Level**: 9 (strictest)
- **Config**: `phpstan.neon`
- **Command**: `composer phpstan`
- **Baseline**: `phpstan-baseline.neon` (exists to track legacy violations)
- **Rule**: New code MUST NOT add to baseline
- **Rule**: Ignored errors MUST have inline comments explaining why

#### PHP Version Compatibility
- **Minimum**: PHP 7.4
- **Target**: PHP 8.0
- **Rule**: NEVER use PHP 8.1+ syntax without version check
- **Rule**: ALWAYS use strict typing (`declare(strict_types=1);`) in new files

#### Type Declarations (MANDATORY for New Code)
```php
// REQUIRED
public function get_cart_items( int $limit = 10 ): array {}

// FORBIDDEN
public function get_cart_items( $limit = 10 ) {}
```

#### Null Safety
- ALWAYS use null coalescing operator: `$value = $array['key'] ?? 'default';`
- NEVER use ternary for null checks: `$value = isset($array['key']) ? $array['key'] : 'default';`

### JavaScript Standards

#### ESLint Rules
- **Config**: `@wordpress/scripts` (`.eslintrc.js`)
- **Command**: `npm run lint-js`
- **Fix Command**: `npm run lint-js:fix`
- **Rule**: ZERO ESLint errors in committed code
- **Rule**: Warnings must be justified with inline comment

#### Prettier Rules
- **Config**: `wp-prettier` standards
- **Command**: `npm run pretty`
- **Fix Command**: `npm run pretty:fix`
- **Pre-commit**: MUST run `npm run pretty:fix` before committing JS

#### React Standards
- **Version**: React 18
- **Patterns**: Functional components ONLY (no class components)
- **Hooks**: Allowed and encouraged
- **PropTypes**: REQUIRED for all components
- **Rule**: NO direct DOM manipulation (use refs sparingly)

#### Frontend JavaScript Standards
- **jQuery**: Allowed for WooCommerce compatibility only
- **Vanilla JS**: Preferred for new code
- **ES6+**: Allowed but MUST be transpiled (use Babel)
- **Global Variables**: ONLY `moderncart_settings` and WooCommerce globals

### CSS Standards

#### Stylelint Rules
- **Config**: WordPress stylelint rules
- **Command**: `npm run lint-css`
- **Fix Command**: `npm run lint-css:fix`
- **Rule**: ZERO stylelint errors in committed code

#### CSS Methodology
- **BEM**: Encouraged but not enforced
- **Prefixing**: ALWAYS prefix classes with `moderncart-` or `mc-`
- **Specificity**: NEVER use `!important` except for overriding WooCommerce/theme styles
- **RTL**: ALWAYS consider RTL (auto-generated by Grunt, but logical properties encouraged)

#### Tailwind CSS
- **Usage**: Allowed in admin React components only
- **Purging**: Configured in PostCSS (unused classes removed)

---

## 5. Commenting & Documentation Rules (NON-NEGOTIABLE)

### PHPDoc Requirements

#### EVERY Function/Method MUST Have
```php
/**
 * Brief description (one line, ends with period).
 *
 * Detailed description if needed (optional, but encouraged for complex logic).
 * Explain WHY this method exists, not just WHAT it does.
 *
 * @since 1.0.0
 * @param string $param1 Description of what param1 represents and its purpose.
 * @param int    $param2 Description including valid ranges or constraints.
 * @return array<string, mixed> Description of return value structure.
 */
public function example_method( string $param1, int $param2 ): array {}
```

#### PHPDoc Rules
- **@since**: REQUIRED for all public methods
- **@param**: REQUIRED for all parameters, MUST describe purpose not just type
- **@return**: REQUIRED for all non-void methods, MUST describe structure for arrays/objects
- **@throws**: REQUIRED if method throws exceptions
- **Type Hints**: MUST match declared types
- **Deprecated**: Use `@deprecated` with version and alternative

### JSDoc Requirements

#### EVERY Function MUST Have
```javascript
/**
 * Brief description (one line).
 *
 * Detailed explanation if needed.
 *
 * @since 1.0.0
 * @param {string} param1 - Description of param1.
 * @param {number} param2 - Description of param2.
 * @return {Object} Description of return object structure.
 */
function exampleFunction( param1, param2 ) {}
```

#### React Component Documentation
```javascript
/**
 * ComponentName - Brief description.
 *
 * Detailed explanation of component purpose and usage.
 *
 * @since 1.0.0
 * @param {Object} props - Component props.
 * @param {string} props.title - Title to display.
 * @param {Function} props.onClick - Click handler.
 * @return {JSX.Element} Rendered component.
 */
```

### Inline Comment Requirements (MANDATORY)

#### EVERY Non-Trivial Line MUST Have a Comment
"Non-trivial" means:
- Complex conditionals
- Array manipulations
- API calls
- Mathematical operations
- Hooks/filters
- Security checks
- Loops with side effects

#### Comment Structure
```php
// Good: Explains WHY
// Verify user has permission to delete cart items before processing AJAX request.
if ( ! current_user_can( 'edit_shop_orders' ) ) {
    wp_send_json_error( 'Insufficient permissions' );
}

// Bad: Explains WHAT (obvious from code)
// Check if user can edit shop orders.
if ( ! current_user_can( 'edit_shop_orders' ) ) {
    wp_send_json_error( 'Insufficient permissions' );
}
```

#### Magic Numbers/Strings MUST Have Comments
```php
// Bad
if ( $count > 5 ) {}

// Good
// Limit cart items display to 5 to prevent layout overflow.
if ( $count > 5 ) {}
```

### File Header Requirements

#### PHP Files
```php
<?php
/**
 * Brief description of file purpose.
 *
 * @package ModernCart
 * @since 1.0.0
 */

namespace ModernCart\Inc;

// File contents...
```

#### JavaScript Files
```javascript
/**
 * Brief description of file purpose.
 *
 * @package ModernCart
 * @since 1.0.0
 */

// File contents...
```

### Forbidden Comment Patterns
- `// TODO` without issue number (use `// TODO #123: Description`)
- `// FIXME` without explanation
- `// Hack` without justification and plan to remove
- Commented-out code (delete it, Git history preserves it)
- Apologetic comments ("Sorry", "I know this is bad")

---

## 6. Code Structure Rules

### Method/Function Length Limits
- **Maximum Lines**: 50 lines per method/function (excluding comments)
- **Ideal**: 20 lines or fewer
- **Exception**: Template rendering methods (100 lines max)
- **Enforcement**: PHPStan and manual code review

### Function Complexity Limits
- **Maximum Cyclomatic Complexity**: 10
- **Ideal**: 5 or fewer
- **Tool**: PHP_CodeSniffer with complexity sniff
- **Rule**: If complexity > 10, refactor into smaller functions

### Early Returns (REQUIRED)

#### Pattern: Guard Clauses at Top
```php
// Good: Early returns for error conditions
public function process_cart() {
    // Guard: Verify WooCommerce is active.
    if ( ! function_exists( 'WC' ) ) {
        return false;
    }

    // Guard: Verify cart exists.
    if ( ! WC()->cart ) {
        return false;
    }

    // Guard: Verify cart is not empty.
    if ( WC()->cart->is_empty() ) {
        return false;
    }

    // Main logic here...
    return $this->render_cart();
}

// Bad: Nested conditionals
public function process_cart() {
    if ( function_exists( 'WC' ) ) {
        if ( WC()->cart ) {
            if ( ! WC()->cart->is_empty() ) {
                return $this->render_cart();
            }
        }
    }
    return false;
}
```

### Nesting Depth (MAXIMUM: 3 levels)
```php
// Bad: 4 levels of nesting
if ( $condition1 ) {
    if ( $condition2 ) {
        if ( $condition3 ) {
            if ( $condition4 ) {
                // Too deep!
            }
        }
    }
}

// Good: Early returns reduce nesting
if ( ! $condition1 ) {
    return;
}
if ( ! $condition2 ) {
    return;
}
if ( ! $condition3 ) {
    return;
}
// Main logic at depth 1
```

### Single Responsibility per Method

#### Forbidden: Mixed Responsibilities
```php
// Bad: Does validation, processing, and rendering
public function handle_ajax() {
    $nonce = $_POST['nonce'];
    if ( ! wp_verify_nonce( $nonce, 'cart_action' ) ) {
        wp_send_json_error();
    }
    $product_id = intval( $_POST['product_id'] );
    WC()->cart->add_to_cart( $product_id );
    $html = $this->render_cart();
    wp_send_json_success( array( 'html' => $html ) );
}
```

#### Required: Separated Responsibilities
```php
// Good: Each method has one responsibility
public function handle_ajax() {
    $this->verify_ajax_request();
    $product_id = $this->get_product_id_from_request();
    $this->add_product_to_cart( $product_id );
    $this->send_success_response();
}
```

### Method Visibility Rules
- **Public**: Only if called outside class
- **Protected**: For inheritance (rare in this plugin)
- **Private**: Default for internal methods
- **Rule**: Minimize public API surface

---

## 7. Security & Data Handling

### Input Sanitization (MANDATORY)

#### AJAX Requests
```php
// ALWAYS verify nonce first
if ( ! check_ajax_referer( 'moderncart_nonce', 'nonce', false ) ) {
    wp_send_json_error( 'Invalid security token' );
}

// Sanitize based on expected type
$product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
$quantity   = isset( $_POST['quantity'] ) ? absint( $_POST['quantity'] ) : 1;
$coupon     = isset( $_POST['coupon'] ) ? sanitize_text_field( $_POST['coupon'] ) : '';
```

#### Sanitization Function Map
- `absint()` - Positive integers (IDs, counts)
- `intval()` - Any integer (can be negative)
- `floatval()` - Decimal numbers
- `sanitize_text_field()` - Single-line text
- `sanitize_textarea_field()` - Multi-line text
- `sanitize_email()` - Email addresses
- `esc_url_raw()` - URLs (before storage)
- `wp_kses_post()` - HTML content (limited tags)

### Output Escaping (MANDATORY)

#### Template Escaping
```php
// Text content
<div><?php echo esc_html( $text ); ?></div>

// Attributes
<div class="<?php echo esc_attr( $class ); ?>"></div>

// URLs
<a href="<?php echo esc_url( $url ); ?>">Link</a>

// JavaScript
<script>
var config = <?php echo wp_json_encode( $config ); ?>;
</script>

// HTML with allowed tags
<div><?php echo wp_kses_post( $content ); ?></div>
```

#### NEVER
- Output `$_POST`, `$_GET`, `$_REQUEST` directly
- Output database results without escaping
- Use `echo` without escaping function

### Nonce Handling

#### Creating Nonces
```php
// In PHP (for forms)
wp_nonce_field( 'moderncart_action', 'moderncart_nonce' );

// In JavaScript (for AJAX)
wp_localize_script( 'moderncart-script', 'moderncart_settings', array(
    'nonce' => wp_create_nonce( 'moderncart_nonce' ),
) );
```

#### Verifying Nonces
```php
// Form submissions
if ( ! isset( $_POST['moderncart_nonce'] ) || ! wp_verify_nonce( $_POST['moderncart_nonce'], 'moderncart_action' ) ) {
    wp_die( 'Security check failed' );
}

// AJAX requests
if ( ! check_ajax_referer( 'moderncart_nonce', 'nonce', false ) ) {
    wp_send_json_error( 'Invalid nonce' );
}
```

#### Nonce Rules
- ALWAYS verify nonces before processing sensitive actions
- NEVER use same nonce name for different actions
- ALWAYS use specific action names (not "moderncart_general")

### Capability Checks

#### User Permissions
```php
// Admin actions
if ( ! current_user_can( 'manage_options' ) ) {
    wp_die( 'Unauthorized' );
}

// Shop manager actions
if ( ! current_user_can( 'edit_shop_orders' ) ) {
    wp_send_json_error( 'Insufficient permissions' );
}
```

#### Capability Rules
- ALWAYS check capabilities for admin actions
- NEVER assume user is logged in
- Use WooCommerce capabilities when appropriate

### WooCommerce Session Safety

#### Session Access Pattern
```php
// Good: Check for WooCommerce and session existence
if ( function_exists( 'WC' ) && WC()->session ) {
    WC()->session->set( 'key', $value );
}

// Bad: Assume session exists
WC()->session->set( 'key', $value ); // Fatal error if WC not active
```

### Database Queries (Direct queries FORBIDDEN)

#### Use WordPress APIs
```php
// Good: Use WordPress API
$option = get_option( 'moderncart_settings', array() );

// Bad: Direct query
global $wpdb;
$result = $wpdb->get_var( "SELECT option_value FROM {$wpdb->options} WHERE option_name = 'moderncart_settings'" );
```

#### Exception: Complex Queries
- Direct queries allowed ONLY for complex reports/analytics
- MUST use `$wpdb->prepare()` for ALL dynamic values
- MUST document why WordPress API is insufficient

### SQL Injection Prevention
```php
// ALWAYS use prepare() for dynamic values
$results = $wpdb->get_results(
    $wpdb->prepare(
        "SELECT * FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s",
        'product',
        'publish'
    )
);
```

### Backward Compatibility

#### Settings Migration
- NEVER remove old option keys without migration function
- ALWAYS provide fallback to old keys for 2+ major versions
- Document migration in upgrade routine

#### API Deprecation
- Mark deprecated methods with `@deprecated` tag
- Provide alternative in deprecation message
- Keep deprecated methods for 2+ major versions
- Log deprecation notices in debug mode

---

## 8. Edge Case Philosophy

### Missing Settings Handling

#### Rule: Always Provide Defaults
```php
// Good: Default value ensures no fatal errors
$setting = Helper::get_instance()->get_option( 'enable_cart', 'yes' );

// Bad: Assume setting exists
$setting = get_option( 'moderncart_settings' )['enable_cart']; // Error if key missing
```

#### Default Strategy
- ALL settings MUST have defaults defined in `Helper::get_defaults()`
- ALWAYS use null coalescing or fallback values
- NEVER throw errors for missing optional settings

### Pro Plugin Not Installed

#### Detection Pattern
```php
// Check if Pro is installed and compatible
if ( defined( 'MODERNCART_PRO_VER' ) && version_compare( MODERNCART_PRO_VER, '1.2.0', '>=' ) ) {
    // Pro features available
} else {
    // Use free version logic
}
```

#### Rules
- ALWAYS check Pro version before accessing Pro features
- NEVER fatal error if Pro is missing
- Gracefully degrade to free functionality
- Show admin notice if Pro version is incompatible

### WooCommerce Disabled

#### Detection Pattern
```php
// Check WooCommerce availability before instantiating classes
if ( ! class_exists( 'WooCommerce' ) ) {
    add_action( 'admin_notices', array( $this, 'woocommerce_missing_notice' ) );
    return;
}
```

#### Rules
- ALWAYS check `class_exists( 'WooCommerce' )` before accessing WC() or WooCommerce classes
- DO NOT load plugin classes if WooCommerce is missing
- Show admin notice with clear message
- DO NOT attempt to activate WooCommerce programmatically

### Empty Cart States

#### Handling Empty Carts
```php
// Always check cart existence and contents
if ( ! function_exists( 'WC' ) || ! WC()->cart || WC()->cart->is_empty() ) {
    return $this->render_empty_cart_message();
}
```

#### Rules
- ALWAYS provide empty cart UI (not blank screen)
- Show "Continue Shopping" link
- DO NOT throw errors for empty carts
- Log debug info if unexpected empty state

### AJAX Failures

#### Error Response Pattern
```php
// Structured error response
wp_send_json_error( array(
    'message' => __( 'Failed to add product to cart', 'modern-cart' ),
    'code'    => 'add_to_cart_failed',
    'debug'   => MODERNCART_DEBUG ? $error_details : null,
) );
```

#### Rules
- ALWAYS send JSON response (never `die()` with text)
- Include user-friendly error message
- Include error code for client-side handling
- Include debug info only if `MODERNCART_DEBUG` is true
- Log errors to PHP error log

### Version Mismatches

#### Compatibility Checks
```php
// Check minimum WordPress version
global $wp_version;
if ( version_compare( $wp_version, '5.4', '<' ) ) {
    return; // Don't load plugin
}

// Check minimum WooCommerce version
if ( version_compare( WC()->version, '3.0', '<' ) ) {
    return; // Don't load plugin
}
```

#### Rules
- Check versions at plugin load time
- DO NOT attempt to load if requirements not met
- Show admin notice with required versions
- DO NOT modify WordPress or WooCommerce versions

### Performance Fallback Strategies

#### Caching Strategy
```php
// Use transients for expensive operations
$cached = get_transient( 'moderncart_cart_data' );
if ( false === $cached ) {
    $cached = $this->calculate_expensive_data();
    set_transient( 'moderncart_cart_data', $cached, HOUR_IN_SECONDS );
}
```

#### Rules
- Cache expensive WooCommerce queries (transients, object cache)
- Set reasonable expiration times (NOT permanent)
- Invalidate cache when relevant data changes
- Provide fallback if cache fails

#### Large Cart Handling
```php
// Limit items displayed in cart preview
$max_items = 10; // Prevent UI overflow
$items = array_slice( WC()->cart->get_cart(), 0, $max_items );
```

#### Rules
- Impose limits on displayed items (10-20 max)
- Show "View Full Cart" link if items exceed limit
- DO NOT load all data if unnecessary
- Use pagination or "Load More" for large datasets

---

## 9. AI-Specific Rules (CRITICAL)

### Refactoring Restrictions

#### AI MUST NEVER:
1. Refactor code outside the immediate task scope
2. "Improve" working code that wasn't identified as problematic
3. Change variable names for "clarity" unless ambiguous
4. Reformat code that already passes linting
5. Add abstraction layers "for future scalability"
6. Replace working patterns with "better" patterns
7. Consolidate similar code into helpers without explicit request

#### Example: BAD AI Behavior
```
User: "Fix typo in admin-menu.php line 42"
AI: "I've fixed the typo and also refactored the entire class to use dependency injection, renamed variables for clarity, and extracted 3 helper methods."
```

#### Example: GOOD AI Behavior
```
User: "Fix typo in admin-menu.php line 42"
AI: "Fixed typo on line 42: 'setings' → 'settings'"
```

### Public API Preservation

#### Rule: NEVER Break Public APIs
- Public methods, filters, hooks are contracts
- Changing signatures breaks user code
- Deprecate old methods, add new methods
- Document BC breaks in comments

#### Justification Required
If AI must change public API:
```php
/**
 * BREAKING CHANGE: Modified method signature to accept array instead of string.
 * Previous signature: public function method( string $param )
 * New signature: public function method( array $params )
 * Reason: Multiple parameters needed for new feature X.
 * Affects: External plugins using this method (estimated: low usage).
 * Migration: Update calls to pass array( 'param' => $value ).
 * @since 1.1.0
 */
```

### Minimal Diff Preference

#### Rule: Smallest Possible Change
```php
// Bad: Changes indentation, adds comments, renames variables
public function get_cart_count() {
    // Get cart instance
    $cart_instance = WC()->cart;

    // Return item count
    return $cart_instance->get_cart_contents_count();
}

// Good: Only fixes the actual bug (missing null check)
public function get_cart_count() {
    if ( ! WC()->cart ) {
        return 0;
    }
    return WC()->cart->get_cart_contents_count();
}
```

#### Diff Checklist Before Committing
- [ ] Every changed line directly addresses the task
- [ ] No formatting-only changes
- [ ] No "while I'm here" improvements
- [ ] No renamed variables unless necessary
- [ ] No added comments unless explaining new logic

### Explain Changes in Comments

#### Rule: Justify Non-Obvious Changes
```php
// Good: Explains WHY change was made
// Changed from WC()->cart->get_cart() to WC()->cart->get_cart_contents()
// because get_cart() includes keys while get_cart_contents() returns indexed array,
// which is required for array_slice() in subsequent line (fixes #123).
$items = WC()->cart->get_cart_contents();
```

### Respect Existing Patterns

#### Rule: Match Repository Style
If repository uses:
- Singleton pattern → Use singleton pattern (don't suggest dependency injection)
- Procedural hooks → Use procedural hooks (don't suggest OOP observers)
- jQuery → Use jQuery (don't suggest Vanilla JS refactor)
- Underscores in class names → Use underscores (don't suggest PascalCase)

#### Exception: Security or Performance
- AI MAY suggest pattern changes for security vulnerabilities
- AI MAY suggest pattern changes for significant performance issues
- MUST document why existing pattern is insufficient

### No Speculative Improvements

#### Forbidden AI Suggestions
- "I've added error handling in case..."
- "I've made this more flexible for future use..."
- "I've extracted this to a helper method..."
- "I've added type hints for better IDE support..."

#### Allowed AI Improvements
- Security vulnerabilities identified during task
- Performance bottlenecks directly related to task
- Logic errors discovered during implementation
- Missing documentation for modified code

---

## 10. Explicit DOs & DON'Ts

### Contributors MUST DO

#### Before Writing Code
- [ ] Read relevant `CLAUDE.md` and `agent.md` sections
- [ ] Search codebase for existing patterns to follow
- [ ] Check `Helper::get_defaults()` for relevant settings
- [ ] Verify WooCommerce and WordPress compatibility

#### While Writing Code
- [ ] Add PHPDoc/JSDoc to every function
- [ ] Add inline comments for non-obvious logic
- [ ] Use early returns and guard clauses
- [ ] Sanitize ALL inputs, escape ALL outputs
- [ ] Verify nonces for AJAX and form submissions
- [ ] Check WooCommerce existence before accessing WC()
- [ ] Use existing helper methods instead of reinventing
- [ ] Follow singleton pattern for new classes

#### Before Committing
- [ ] Run `composer format` (PHP)
- [ ] Run `npm run lint-js:fix` (JavaScript)
- [ ] Run `npm run pretty:fix` (Formatting)
- [ ] Run `npm run build` (React admin)
- [ ] Run `grunt minify` (Frontend assets)
- [ ] Test in browser with WooCommerce active
- [ ] Test with WooCommerce inactive (should fail gracefully)
- [ ] Verify no PHPStan errors introduced
- [ ] Check git diff for unintended changes

### Contributors MUST NEVER DO

#### Code Structure
- ❌ Create global variables (use class properties or constants)
- ❌ Use global namespace for plugin classes
- ❌ Mix HTML and PHP logic (use templates)
- ❌ Put business logic in templates
- ❌ Create classes without singleton trait (unless justified)
- ❌ Directly instantiate classes (use `::get_instance()`)

#### Security
- ❌ Output unsanitized user input
- ❌ Process form/AJAX data without nonce verification
- ❌ Perform admin actions without capability checks
- ❌ Use direct SQL queries without `$wpdb->prepare()`
- ❌ Trust client-side data

#### Compatibility
- ❌ Assume WooCommerce is active
- ❌ Assume Pro plugin is installed
- ❌ Use PHP 8.1+ syntax without version check
- ❌ Break backward compatibility without deprecation
- ❌ Remove deprecated code within 2 major versions

#### Build & Assets
- ❌ Edit minified files directly
- ❌ Commit `node_modules/` or `vendor/`
- ❌ Edit build artifacts (edit source and rebuild)
- ❌ Skip linting before commit
- ❌ Commit code with linting errors

#### Documentation
- ❌ Skip PHPDoc for public methods
- ❌ Write "obvious" comments (e.g., `// Check if true`)
- ❌ Leave TODO without issue number
- ❌ Commit commented-out code
- ❌ Use vague parameter descriptions

### Common Anti-Patterns FORBIDDEN in This Repository

#### Anti-Pattern 1: God Object
```php
// FORBIDDEN: Class that does everything
class Cart_Manager {
    public function handle_ajax() {}
    public function render_cart() {}
    public function calculate_totals() {}
    public function send_email() {}
    public function log_analytics() {}
}
```
**Fix**: Separate into `Cart_Ajax`, `Cart`, `Cart_Calculator`, `Cart_Email`, `Cart_Analytics`

#### Anti-Pattern 2: Hardcoded Values
```php
// FORBIDDEN
if ( $cart_count > 5 ) {}

// REQUIRED
// Limit cart preview to 5 items to prevent UI overflow (configurable in future via filter).
$max_preview_items = 5;
if ( $cart_count > $max_preview_items ) {}
```

#### Anti-Pattern 3: Mixed Responsibilities
```php
// FORBIDDEN: Validation, business logic, and rendering in one method
public function process_checkout() {
    if ( empty( $_POST['email'] ) ) {
        echo 'Email required';
        return;
    }
    $order = wc_create_order();
    echo '<h1>Thank you</h1>';
}
```
**Fix**: Separate into validation, processing, and template rendering

#### Anti-Pattern 4: Nested Conditionals
```php
// FORBIDDEN
if ( $a ) {
    if ( $b ) {
        if ( $c ) {
            if ( $d ) {
                // Deep nesting
            }
        }
    }
}
```
**Fix**: Use early returns or extract to separate methods

#### Anti-Pattern 5: Silent Failures
```php
// FORBIDDEN
public function add_to_cart( $product_id ) {
    if ( ! $product_id ) {
        return; // Fails silently
    }
}
```
**Fix**: Log errors, return meaningful error codes, or throw exceptions

#### Anti-Pattern 6: Stringly-Typed Code
```php
// FORBIDDEN
function get_cart_type() {
    return 'slide-out'; // String instead of constant
}
```
**Fix**: Use class constants or enums (PHP 8.1+)

#### Anti-Pattern 7: Copy-Paste Code
```php
// FORBIDDEN: Duplicated logic in two places
public function slide_out_add_to_cart() {
    $product_id = intval( $_POST['product_id'] );
    $quantity = intval( $_POST['quantity'] );
    WC()->cart->add_to_cart( $product_id, $quantity );
}

public function floating_add_to_cart() {
    $product_id = intval( $_POST['product_id'] );
    $quantity = intval( $_POST['quantity'] );
    WC()->cart->add_to_cart( $product_id, $quantity );
}
```
**Fix**: Extract to shared method in `Cart` class

#### Anti-Pattern 8: Ignored Errors
```php
// FORBIDDEN
@include 'template.php'; // Suppresses errors
```
**Fix**: Handle errors explicitly or let them surface

---

## Compliance & Enforcement

This document is **strictly enforced**. Code that violates these rules will be:
1. Rejected in code review
2. Flagged by automated linting tools
3. Blocked by pre-commit hooks (if configured)

**Zero Tolerance Policy**:
- No exceptions for "quick fixes"
- No "I'll clean it up later"
- No "it works, don't touch it"

**AI Agents**: You are expected to reference this document before every code change. When in doubt, ask for clarification rather than assuming.

**Human Contributors**: You are expected to internalize these rules. Repeated violations will result in contribution privileges being revoked.

---

**Last Updated**: 2026-01-14
**Document Version**: 1.0.0
**Maintained By**: Modern Cart Core Team
