# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What this is

WordPress plugin **Affiliate Super Assistent (ASA1)** — embeds Amazon affiliate products into WordPress posts via `[asa]ASIN[/asa]` and `[asa_collection]name[/asa_collection]` shortcodes. Text domain `asa1`. Requires PHP 8.1+, WordPress 5.1+. Current version in `amazonsimpleadmin.php` and `readme.txt` (`Stable tag`).

The repository directory is an SVN working copy. The plugin code lives under `trunk/`; siblings `tags/`, `branches/`, `assets/` and `resources/` are part of the WordPress.org plugin SVN layout. Always work in `trunk/`.

## Working with the plugin locally

Local environment uses `@wordpress/env` (`.wp-env.json`) which maps this `trunk/` directory into `wp-content/plugins/amazonsimpleadmin` of a Dockerized WordPress. PHP 8.4, `WP_DEBUG=true`, debug log piped to `./tmp/debug.log`. Standard wp-env commands (`wp-env start`, `wp-env stop`, `wp-env run cli ...`) apply — there is no project-specific wrapper.

There is no PHPUnit / Composer test setup in this repo. Functional verification happens through the **Test** tab in the plugin's admin page (`Settings → Affiliate Super Assistent (ASA1) → Test`). New PHP classes should still be designed for testability (DI-friendly, no static state where avoidable) per the user's global rules.

## Releasing to WordPress.org (SVN)

Releases use the Node script in the SVN working copy root, not in `trunk/`:

```bash
cd /Volumes/sources/amazonsimpleadmin
node resources/svn/create-tag-v2.mjs <version> --dry-run   # always dry-run first
node resources/svn/create-tag-v2.mjs <version>
```

The script reads/updates `Stable tag` in `trunk/readme.txt`, copies trunk to `tags/<version>/`, strips dev-only files (`.idea/`, `.claude/`, `.security-reports/`, `.wp-env.json`, `tmp/`, `CLAUDE.md`, `GEMINI.md`, `node_modules/`, `.DS_Store`, `asadebug.txt`, `one-theme/`), then commits both the tag and trunk. Bumping the version means updating the `Version:` header in `amazonsimpleadmin.php` AND the `Stable tag:` / `== Changelog ==` in `readme.txt` before tagging.

## Translations

`.pot` and `.po` files live in `lang/` (`asa1.pot`, `asa1-de_DE.po`, etc.). Compile `.po → .mo` with `msgfmt lang/asa1-de_DE.po -o lang/asa1-de_DE.mo`. Per user's global rules: translatable source strings are English, German is supplied via the `de_DE` po file, and never split sentences across multiple `__()` calls — use `printf` with numbered placeholders (`%1$s`, `%2$s`).

## High-level architecture

### Entry point
`amazonsimpleadmin.php` is the WordPress plugin header. It defines `ASA_BASE_FILE` and `ASA_LIB_DIR`, registers the Creators API SDK autoloader (PHP 8.1+ only), then includes the monolith `AsaCore.php`. The class `AmazonSimpleAdmin` in `AsaCore.php` is ~5000 lines and owns: WP hook registration, admin UI rendering, shortcode handlers, options handling, cache initialization, and template rendering. New work usually means extending or routing through this class — but extract into namespaced classes under `lib/Asa/...` whenever possible (per the user's SRP/DRY rule).

`AsaCore.php`'s constructor is the wiring diagram: shortcodes (`asa`, `asa_collection`), filters (`the_excerpt`, `the_content_feed`, `widget_text`, optionally `comment_text`), upgrade hooks (`upgrader_pre_install` / `upgrader_post_install` back up and restore custom templates in `tpl/`), the admin menu, AJAX init (`include/asa_ajax_callback.php` registers `wp_ajax_asa_async_load`).

### Admin pages
The settings page lives at `options-general.php?page=amazonsimpleadmin/amazonsimpleadmin.php`. Sub-pages are routed by `?task=`: `options`, `collections`, `cache`, `usage`, `templates`, `faq`, `test`, `log`, `credits`. The dispatcher methods are `_displayPreDispatcher`, `_beforeOutput`, `_displayDispatcher`. Capability gates live in `AsaCapabilities.php` (custom caps prefixed `asa1_`).

### Amazon service abstraction (the part that matters most)

All Amazon API calls go through the `Asa_Service_Amazon_Interface` interface (`lib/Asa/Service/Amazon/Interface.php`). Three implementations exist, selected by the static factory `Asa_Service_Amazon::factory()`:

1. **`Asa_Service_CreatorsApi`** (`lib/Asa/Service/CreatorsApi.php`) — Amazon Creators API. Used when PHP ≥ 8.1, ASA2 is **not** active, and Creators API credentials are configured (see `Asa_Service_CreatorsApi_Credentials::isUsable()`). Wraps the SDK in `lib/AsaAmazonCreatorsApi/`.
2. **`Asa_Service_PaApi5`** (`lib/Asa/Service/PaApi5.php`) — Default. Amazon PA API 5.0, used in essentially all current installs (`asa_is_pa_api_5()` returns `true` unconditionally).
3. **`Asa_Service_Amazon`** (`lib/Asa/Service/Amazon.php`) — Legacy SOAP/XML PA API. Dead path; kept for reference. Don't add features here.

Selection logic and helpers are in `include/asa_helper_functions.php`: `asa_should_use_creators_api()`, `asa_creators_api_conflict_detected()`, `asa_is_asa2_active()`. **Critical conflict consideration:** when the Pro plugin ASA2 is active, both plugins would load Guzzle. ASA1 ships Guzzle under the rewritten namespace `AsaGuzzleHttp\` (vendor dir `vendor/asaguzzlehttp/...`) precisely to coexist. The Creators API SDK in `lib/AsaAmazonCreatorsApi/` was patched to use `AsaGuzzleHttp` instead of `GuzzleHttp`. If `class_exists('GuzzleHttp\Client', false)` returns true, the Creators API path is silently skipped and PA API is used. Don't introduce a non-prefixed Guzzle import or this fallback breaks.

The Creators API SDK has its own PSR-4-style autoloader for namespace `Amazon\CreatorsAPI\v1\` registered from `lib/AsaAmazonCreatorsApi/autoload.php`.

### Templates
Product output templates are plain HTML files with `{$Placeholder}` markers in `tpl/built-in/` (e.g. `default.htm`, `flat_box_horizontal.htm`, `book.htm`, `dvd.htm`, plus `_de` localized variants and a few CSS companions). User-customized templates also live in `tpl/`. The `backupTemplates()` / `restoreTemplates()` pair in `AsaCore.php` snapshots `tpl/` to the OS temp dir before plugin upgrades and restores afterwards so user customizations survive `upgrader_post_install`.

### Caching
File cache via the bundled `AsaZend_Cache` (`lib/AsaZend/Cache.php`, a vendored slice of old Zend Framework 1) writes to `cache/`. Initialized in `AmazonSimpleAdmin::_initCache()`; controlled via options `_asa_cache_active`, `_asa_cache_dir`, `_asa_cache_lifetime`, `_asa_cache_disable_variable_lifetime`. The directory must be writable by the web server.

### Other library code under `lib/`
- `lib/Asa/Prefetcher.php` — ASIN prefetching for speed (since v1.3).
- `lib/Asa/ItemBuffer.php`, `lib/Asa/Util/Buffer.php` — In-memory item caching during a single request.
- `lib/Asa/CssLoading.php` — Inline/external CSS handling for templates.
- `lib/Asa/Debugger.php` — Optional debug instrumentation, gated by `_asa_debug` option / `ASA_APPLICATION_ENV=development`.
- `lib/AsaAmazon/` — Older PA API client wrapper code (still used internally).

### Top-level companion classes (loaded from `AsaCore.php`)
`AsaCollection.php` and `AsaCollectionImport.php` (collections feature, DB tables `asa_collection` / `asa_collection_item`), `AsaWidget.php` (sidebar widget), `AsaCapabilities.php` (install/uninstall custom caps), `AsaEmail.php` (error notifications, opt-in), `AsaLogger.php` + `AsaLogListTable.php` (Log tab), `AsaCustomerReviews.php`.

## Conventions specific to this codebase

- **No namespaces in legacy code.** Old classes use the underscore-prefixed pseudo-namespace pattern (`Asa_Service_Amazon`, `AsaZend_Cache`). For *new* code, use real PHP namespaces (per user's global rules) — the Creators API integration in `lib/AsaAmazonCreatorsApi/` is the precedent (`Amazon\CreatorsAPI\v1\…`) and gets its own autoloader registration.
- **Vendor namespace prefix.** Every Composer-installed dep is rewritten to a prefixed namespace (`AsaGuzzleHttp\`, etc.) to coexist with ASA2. Don't `composer require` anything new without the same prefixing strategy, and don't import unprefixed `GuzzleHttp\…` from any code path that may run with ASA2 active.
- **All option keys are prefixed `_asa_`.** All nonces are class constants on `AmazonSimpleAdmin` (`NONCE_*`). Reuse them rather than inventing new ones for the same form.
- **Country/locale handling.** Supported codes are listed in `AmazonSimpleAdmin::$_amazon_valid_country_codes` and `Asa_Service_CreatorsApi::$marketplaces`. Both lists must stay in sync when adding/removing a marketplace.
- **`asa_debug($var, $backtrace = false)`** in `include/asa_helper_functions.php` writes to `WP_CONTENT_DIR/debug.log` only when `WP_DEBUG === true` — use this rather than `error_log()` directly.

## Security reports

`.security-reports/owasp-analysis/` contains output from the `owasp-security-analyzer` agent (`latest.md`, `summary.html`). Not committed via the SVN release script (excluded). Re-run the agent before releases when meaningful surface area has changed (admin form handlers, AJAX, shortcode parsing).
