commit f11e1d650da9ca25d6f186b659023aea8a1c08d7
Author: XShop
Date: Sun Sep 13 19:04:41 2026 +0330
chore: complete M1.1 runtime QA and release packaging
diff --git a/shop/.editorconfig b/shop/.editorconfig
new file mode 100644
index 0000000..ec48fee
--- /dev/null
+++ b/shop/.editorconfig
@@ -0,0 +1,15 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 4
+
+[*.{js,css,json,yml,yaml}]
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/shop/.gitignore b/shop/.gitignore
new file mode 100644
index 0000000..8b231d6
--- /dev/null
+++ b/shop/.gitignore
@@ -0,0 +1,16 @@
+release/*.zip
+release/*.log
+# Local test installs (M1.1) – never commit wp-config / debug logs / DB
+xshop-test/
+wp-config.php
+debug.log
+node_modules/
+vendor/
+.env
+.env.*
+*.log
+.DS_Store
+Thumbs.db
+.cache/
+coverage/
+.sass-cache/
diff --git a/shop/CHANGELOG.md b/shop/CHANGELOG.md
new file mode 100644
index 0000000..284b084
--- /dev/null
+++ b/shop/CHANGELOG.md
@@ -0,0 +1,16 @@
+# Changelog
+
+All notable changes to XShop follow [Keep a Changelog](https://keepachangelog.com/) and [SemVer](https://semver.org/).
+
+## [1.0.0] – Unreleased
+
+### Added
+- Phase 0: product spec, architecture, feature matrix, roadmap, UI spec, database model, security, performance, testing, compatibility docs + ADRs.
+- **M1 — Theme Foundation**:
+ - Templates: `header.php`, `footer.php`, `index.php`, `front-page.php` (section-based hero/category/product/promo/latest), `single.php`, `page.php`, `archive.php`, `search.php`, `404.php`, `sidebar.php`, `comments.php` (threaded, paginated, accessible).
+ - Components: `template-parts/components/site-header.php`, `site-footer.php`, `breadcrumbs.php` (Woo-aware, filterable), `pagination.php` (RTL-safe), `search-form.php`, `post-card.php`, `empty-state.php`, `loading.php`, `section-heading.php`, `hero.php`, `promo-banner.php`.
+ - Design system: finalized `assets/css/tokens.css` (full palette/typography/spacing/radius/shadow/z/transition + dark mode semantic swap), `base.css`, `layout.css`, `components.css`, `utilities.css` — logical properties, zero `left`/`right`.
+ - JS: `assets/js/theme.js` extended with accessible mobile nav (aria-expanded, focus trap, Esc, click-outside) + dark-mode toggle.
+ - PHP: `inc/helpers/template.php` (xshop_has_woocommerce, xshop_is_woocommerce_page, branding fallback), `inc/setup/body-classes.php`, `inc/setup/assets.php` (layered enqueue + Woo style dequeue), `inc/woocommerce/setup.php` (wrappers).
+ - Docs: updated `docs/ARCHITECTURE.md`, `docs/UI-SPEC.md`, `docs/TESTING.md` for M1.
+
diff --git a/shop/README.md b/shop/README.md
new file mode 100644
index 0000000..e587fa2
--- /dev/null
+++ b/shop/README.md
@@ -0,0 +1,40 @@
+# XShop — Persian-first WooCommerce Theme + Companion Plugin
+
+Commercial, RTL/LTR, responsive, accessible, performant. Sold on RTL-Theme / راستچین.
+
+## Components
+
+- `xshop-theme/` — presentation (templates, design system, RTL, header/footer builders).
+- `xshop-core/` — functionality (wishlist, compare, Q&A, AJAX search/filter, banners, demo import).
+
+## Docs
+
+- `docs/PRODUCT-SPEC.md` — product spec
+- `docs/ARCHITECTURE.md` — architecture
+- `docs/FEATURE-MATRIX.md` — feature matrix
+- `docs/ROADMAP.md` — roadmap & phases
+- `docs/UI-SPEC.md` — design system
+- `docs/DATABASE-MODEL.md` — data model
+- `docs/SECURITY.md` — security
+- `docs/PERFORMANCE.md` — performance
+- `docs/TESTING.md` — testing
+- `docs/COMPATIBILITY.md` — compatibility
+- `docs/ADR/` — architecture decision records
+
+## Requirements
+
+- WordPress 6.4+, WooCommerce 8.0+, PHP 8.2+, modern browsers.
+
+## Quick Start (dev)
+
+1. Copy `xshop-theme/` to `wp-content/themes/xshop/`.
+2. Copy `xshop-core/` to `wp-content/plugins/xshop-core/`.
+3. Activate theme + plugin. Run setup wizard (XShop → Setup Wizard).
+
+## Development Principles
+
+See `docs/ARCHITECTURE.md` and `AGENTS.md` (if present). No TODO placeholders in releases. WC is source of truth for commerce; WP for content.
+
+## License
+
+Commercial. Third-party assets documented in `xshop-theme/docs/` and `CHANGELOG.md`.
diff --git a/shop/docs/ADR/001-no-custom-tables-v1.md b/shop/docs/ADR/001-no-custom-tables-v1.md
new file mode 100644
index 0000000..710b0c7
--- /dev/null
+++ b/shop/docs/ADR/001-no-custom-tables-v1.md
@@ -0,0 +1,17 @@
+# ADR 001 – No Custom Tables in v1
+
+**Status**: Accepted
+
+## Context
+
+Wishlist/compare/Q&A/banners could use custom tables for performance. Customs add migration/upgrade burden and risk for a commercial theme sold on RTL-Theme where host environments vary.
+
+## Decision
+
+Store all v1 data in WP primitives: CPT (`xshop_banner`, `xshop_qa`), `wp_usermeta` + cookies for wishlist/compare, single option `xshop_settings`. No custom tables.
+
+## Consequences
+
+- Simpler install/uninstall, no `dbDelta` fragility.
+- Query performance acceptable at ≤100k products; revisit if profiling shows bottleneck.
+- Future ADR can introduce tables with migration path.
diff --git a/shop/docs/ADR/002-rest-over-admin-ajax.md b/shop/docs/ADR/002-rest-over-admin-ajax.md
new file mode 100644
index 0000000..a10cdda
--- /dev/null
+++ b/shop/docs/ADR/002-rest-over-admin-ajax.md
@@ -0,0 +1,17 @@
+# ADR 002 – REST API as Primary for AJAX
+
+**Status**: Accepted
+
+## Context
+
+Search/filter/wishlist/compare/Q&A need async endpoints. `admin-ajax.php` is uncacheable and fires `admin_init`. REST is cache-friendly and has `permission_callback`.
+
+## Decision
+
+- REST (`xshop/v1/*`) for search, filter, wishlist, compare, Q&A.
+- Keep `admin-ajax` only where WC core expects it (cart fragments/mini-cart) or as fallback.
+
+## Consequences
+
+- Requires nonce via `X-WP-Nonce` + localized `wpApiSettings` or custom `xshopData.nonce`.
+- Better compatibility with caching plugins; clearer permission model.
diff --git a/shop/docs/ARCHITECTURE.md b/shop/docs/ARCHITECTURE.md
new file mode 100644
index 0000000..9cd19f7
--- /dev/null
+++ b/shop/docs/ARCHITECTURE.md
@@ -0,0 +1,163 @@
+# XShop – Architecture (v1.0.0)
+
+## 1. Overview
+
+```
+repo/
+ docs/ # product specs & ADRs
+ xshop-theme/ # presentation layer
+ xshop-core/ # companion plugin
+ release/ # built zips (not committed)
+ tools/ # build / QA scripts
+```
+
+Two installable artifacts: theme (`xshop`) + plugin (`xshop-core`). Theme never stores business logic that outlives theme activation (wishlist/compare/Q&A/banners live in plugin).
+
+## 2. Theme – `xshop-theme`
+
+### 2.1 File map (M1)
+
+```
+xshop-theme/
+ style.css # WP header
+ functions.php # thin loader (requires inc/setup/* only)
+ screenshot.png # placeholder until final artwork
+ rtl.css # WP RTL flag; logical props used, not duplicated stylesheet
+ header.php # + skip link + xshop-header wrapper + breadcrumbs
+ footer.php # + footer + wp_footer
+ index.php / front-page.php / single.php / page.php / archive.php / search.php / 404.php / sidebar.php / comments.php
+ inc/
+ setup/ # theme-support, menus, sidebars, body-classes, assets
+ helpers/ # sanitize, template (xshop_get_setting, xshop_svg, xshop_is_dark_mode, xshop_has_woocommerce, branding fallback)
+ customization/ # options (xshop_settings) — full UI in M6
+ compatibility/ # gutenberg, elementor (no hard dep)
+ woocommerce/ # wrappers + dequeued WC styles + notice compat
+ performance/ # defer for xshop.js
+ assets/
+ css/ # tokens, base, layout, components, utilities
+ js/ # theme.js (mobile nav + dark toggle + focus trap)
+ images/ fonts/
+ template-parts/components/
+ site-header.php, site-footer.php,
+ breadcrumbs.php, pagination.php, search-form.php, post-card.php,
+ empty-state.php, loading.php, section-heading.php, hero.php, promo-banner.php
+ woocommerce/ # empty in M1 — overrides only when justified (documented)
+ languages/
+```
+
+### 2.2 Bootstrap
+
+`functions.php` is a thin loader:
+
+```php
+require_once __DIR__ . '/inc/setup/theme-support.php';
+require_once __DIR__ . '/inc/setup/menus.php';
+// ... each file exposes a single setup function hooked appropriately
+```
+
+No giant `functions.php`. Each `inc/*` file is namespaced or prefixed `xshop_`.
+
+### 2.3 Namespacing & Prefixing
+
+- Text domain: `xshop`
+- PHP functions/options/actions/meta: `xshop_` prefix.
+- Classes: `XShop\Theme\...` and `XShop\Core\...` (PSR-4 style even if manual require).
+
+### 2.4 Hook Strategy
+
+- Use `after_setup_theme` for theme support, `init` for CPT/taxonomy (only banners/Q&A).
+- Use `wp_enqueue_scripts` with conditional loading.
+- Use WC hooks for pricing, badges, loops – avoid overriding templates unless necessary.
+
+## 3. Plugin – `xshop-core`
+
+```
+xshop-core/
+ xshop-core.php # plugin header + loader
+ includes/
+ Core/ # plugin bootstrap, constants
+ Modules/
+ Wishlist/
+ Compare/
+ QA/
+ Search/
+ Filter/
+ Banners/
+ Badges/
+ DemoImport/
+ SetupWizard/
+ SystemStatus/
+ Widgets/
+ Admin/ # menu, dashboard, settings pages
+ REST/ # REST endpoints (search/filter/wishlist/compare/QA)
+ Compatibility/
+ assets/ css/ js/
+ languages/
+ templates/ # wishlist, compare, banners front-end fragments
+```
+
+Plugin owns persistence for wishlist/compare/Q&A/banners. Theme only renders.
+
+## 4. Data Ownership
+
+- **WC**: products, variations, orders, customers, coupons, shipping, payment, taxes, cart, checkout.
+- **WP**: users, posts, pages, media, menus, comments.
+- **Custom**: banners (CPT `xshop_banner`), Q&A (CPT or comments extension – see DATABASE-MODEL.md), wishlist/compare (user meta + cookie + transient for guests), theme settings (single option `xshop_settings` + mods).
+
+Avoid custom tables in v1; revisit via ADR if scale demands.
+
+## 5. Design System (M1)
+
+CSS custom properties in `assets/css/tokens.css` — full token set: primary/secondary/bg/surface/card/text/muted/border/input/focus/link/success/warning/danger (+ bg variants), typography (xs–4xl, weights 400/500/700, leading tight/normal/relaxed), spacing (1–16), container/narrow, radius (sm/md/lg/full), shadow (sm/md/lg), z, transition (fast/normal/slow). Dark mode semantic swap on `[data-theme="dark"]`. Layering: `tokens→base→layout→components→utilities→style.css` via `inc/setup/assets.php:1`.
+
+Logical properties (`margin-inline`, `padding-inline`, `inset-inline`, `inset-block`, `inline-size`) throughout; zero `left`/`right` in theme CSS. Components consume tokens, never hardcode colours.
+
+## 6. Asset Strategy (M1)
+
+- No jQuery for new code (vanilla JS; `theme.js:1` is deferred). WC jQuery remains for its handlers.
+- Enqueue: `tokens→base→layout→components→utilities→style.css` chain in `inc/setup/assets.php:1` with version `XSHOP_VERSION`; `style.css` declares `rtl` replace. WC styles dequeued (`woocommerce_enqueue_styles` → `__return_empty_array`) to avoid duplication — theme provides compat in `components.css:1`.
+- Conditional: feature modules (search/filter/wishlist) will be enqueued per-template in M5; M1 only loads `theme.js`.
+- Localized `xshopData` (restUrl, nonce, isRtl, i18n) on `xshop` handle.
+- Build: no build step required to activate; release minify via `tools/build-release.ps1`.
+
+## 7. AJAX / REST
+
+Prefer **WP REST API** for search/filter/Q&A (cacheable, nonce via `X-WP-Nonce`), fallback to `admin-ajax` for cart/mini-cart where WC expects it. All endpoints: sanitize → validate → capability check → nonce → escaped output.
+
+## 8. Security Model
+
+See `SECURITY.md`. TL;DR: sanitize in, escape out, nonces, capability checks, prepared statements, no `unserialize`, no open redirects.
+
+## 9. Performance Model
+
+See `PERFORMANCE.md`. Conditional assets, lazy-load, transients for expensive queries, no N+1, `wp_cache`.
+
+## 10. i18n / RTL
+
+- All strings via `__()`, `_e()`, `esc_html__()` with text domain `xshop`.
+- Logical CSS, `dir` attribute toggling, `is_rtl()` branching only where logical props insufficient.
+- Persian typography tokens, `lang="fa"` support, mixed LTR numbers handled via `unicode-bidi` where needed.
+
+## 11. Templating (M1)
+
+`header.php:1` renders `site-header.php:1` + `breadcrumbs:1` (except front/404); `footer.php:1` renders `site-footer.php:1`. All content templates (`index.php:1`, `front-page.php:1`, `single.php:1`, `page.php:1`, `archive.php:1`, `search.php:1`, `404.php:1`) use Loop + `get_template_part()` + `comments_template()` / `dynamic_sidebar()` where appropriate. Reusable components: `breadcrumbs`, `pagination`, `search-form`, `post-card`, `empty-state`, `loading`, `section-heading`, `hero`, `promo-banner`. No markup duplication. `front-page.php:1` is section-based (hero, category grid, product grid via `wc_get_products`, promo, latest posts) — extensible via `xshop_front_hero_args` filter.
+
+WC overrides: none in M1; wrappers via `woocommerce_before_main_content`/`after_main_content` in `inc/woocommerce/setup.php:1`. Future overrides documented in `docs/woocommerce.md` with version map.
+
+## 12. Decision Records
+
+ADRs in `docs/ADR/` – one per major decision (e.g., “No custom tables for Q&A in v1”).
+
+## 13. Release
+
+`release/xshop.zip` + `release/xshop-core.zip` built via `tools/build-release.ps1`. Excludes `.git`, `node_modules`, `.env`, logs, temp.
+
+## 14. Versioning
+
+SemVer 1.0.0. `CHANGELOG.md` follows Keep a Changelog.
+
+## 15. Risks & Mitigations
+
+- WC API churn → pin tested versions, monitor template versions, use hooks not overrides.
+- RTL regressions → logical props + visual regression checklist.
+- Demo import timeouts → chunked importer with resume.
diff --git a/shop/docs/COMPATIBILITY.md b/shop/docs/COMPATIBILITY.md
new file mode 100644
index 0000000..62f4f4d
--- /dev/null
+++ b/shop/docs/COMPATIBILITY.md
@@ -0,0 +1,46 @@
+# XShop – Compatibility
+
+## 1. Tested Up To
+
+| Dependency | Minimum | Tested |
+|------------|---------|--------|
+| WordPress | 6.4 | 6.6.x |
+| WooCommerce| 8.0 | 9.x |
+| PHP | 8.2 | 8.2, 8.3 |
+| Elementor | 3.15 (optional) | 3.2x |
+| Gutenberg | WP bundled | — |
+| Browsers | last 2 versions: Chrome, Firefox, Edge, Safari | — |
+
+## 2. WordPress APIs Used
+
+- Theme support: `add_theme_support('title-tag','post-thumbnails','html5','custom-logo','woocommerce'...)`
+- Menus/sidebars/widgets: `register_nav_menus`, `register_sidebar`, `widgets_init`.
+- Settings: `register_setting` + single option `xshop_settings` (Settings API).
+- Customizer: `customize_register` for preview (typography/colours).
+- REST: `register_rest_route` (namespace `xshop/v1`).
+
+## 3. WooCommerce Integration
+
+- Declared `add_theme_support('woocommerce')` + gallery features (`wc-product-gallery-zoom/lightbox/slider`).
+- Wrapper via `woocommerce_before_main_content` / `after_main_content`.
+- Hooks over template overrides. Overrides documented in `docs/woocommerce.md` with WC version map; monitor `WC()->version` and template `Version:` header.
+
+## 4. HPOS
+
+- Uses `wc_get_products` CRUD, not direct post table writes. Compatible with High-Performance Order Storage. No direct `wp_posts` manipulation for orders.
+
+## 5. Elementor
+
+- Widgets registered via `\Elementor\Plugin::instance()->widgets_manager->register` if Elementor active. Namespaced `XShop\Core\Elementor\Widgets\*`. No hard dependency – `is_plugin_active` guard.
+
+## 6. Gutenberg
+
+- Block styles via `register_block_style`, theme.json opt-in later. No classic-editor dependency.
+
+## 7. Multisite
+
+- Not primary target; options are per-site (no network options in v1).
+
+## 8. Upgrade Notes
+
+- Template version bumps checked via `WC template version` comment. Override only where necessary; changelog notes any override update.
diff --git a/shop/docs/DATABASE-MODEL.md b/shop/docs/DATABASE-MODEL.md
new file mode 100644
index 0000000..e439dd2
--- /dev/null
+++ b/shop/docs/DATABASE-MODEL.md
@@ -0,0 +1,80 @@
+# XShop – Database Model
+
+## 1. Philosophy
+
+Reuse WP/WC primitives. No custom tables in v1.0 – revisit via ADR if query scale warrants. Document every key.
+
+## 2. WordPress-Owned
+
+- **Users** (`wp_users`, `wp_usermeta`): native. XShop adds: `xshop_wishlist` (array of product IDs), `xshop_compare` (array), `xshop_recently_viewed` (capped list).
+- **Posts/Pages** (`wp_posts`, `wp_postmeta`): native.
+- **Media** (`wp_posts` attachment): native.
+- **Menus** (`wp_terms` nav_menu): native.
+- **Comments/Reviews**: WC reviews = WP comments on `product` post type. XShop Q&A moderation hooks onto comment moderation flow where applicable – but primary store is custom (below).
+
+## 3. WooCommerce-Owned
+
+- **Products** (`wp_posts` post_type `product` + `wp_postmeta` + `wp_wc_*` where HPOS enabled). Variations are `product_variation` children.
+- **Orders/Customers/Coupons/Shipping/Payment/Taxes/Cart/Checkout**: WC owned (HPOS tables if enabled). XShop never writes directly to WC order tables except via WC APIs.
+
+## 4. XShop-Core Custom Data
+
+### 4.1 Banners – CPT `xshop_banner`
+
+- `post_type = xshop_banner` (non-public, `show_ui` true under XShop menu).
+- Meta:
+ - `_xshop_banner_image` (attachment ID, int)
+ - `_xshop_banner_mobile_image` (attachment ID, int, nullable)
+ - `_xshop_banner_link` (url, esc_url_raw)
+ - `_xshop_banner_cta` (string)
+ - `_xshop_banner_position` (enum: `home_hero`, `home_strip`, `shop_top`, `product_sidebar`, etc.)
+ - `_xshop_banner_active` (`1`|`0`)
+ - `_xshop_banner_start` / `_xshop_banner_end` (datetime Y-m-d H:i:s, UTC)
+ - `_xshop_banner_order` (int)
+- Scheduling checked on render (skip if outside window or inactive).
+
+### 4.2 Questions & Answers – CPT `xshop_qa`
+
+Decision: CPT (not comments) for cleaner moderation + threading without polluting reviews.
+
+- `post_type = xshop_qa`, `post_parent` = product ID (or meta `_xshop_qa_product_id` for query flexibility – both stored, parent is canonical).
+- Post fields: `post_title` empty, `post_content` = question body, `post_status` = `pending`|`publish`|`trash`, `post_author` = asker.
+- Meta:
+ - `_xshop_qa_product_id` (int, indexed via meta query)
+ - `_xshop_qa_answer` (string, nullable – single answer for v1; extension to multiple answers uses child `xshop_qa` rows with `post_parent` = question ID in v1.1)
+ - `_xshop_qa_answered_by` (int user ID)
+ - `_xshop_qa_answered_at` (datetime)
+- Alternative for multiple answers (future): child posts `post_type=xshop_qa`, `post_parent=question ID`.
+- Spam: honeypot + nonce + rate limit (transient per IP/user, 60s).
+
+### 4.3 Wishlist & Compare
+
+- **Logged-in**: `wp_usermeta` keys `xshop_wishlist`, `xshop_compare` (serialized array of ints, capped: wishlist 200, compare 4).
+- **Guest**: cookie `xshop_wishlist` / `xshop_compare` (JSON, HttpOnly false for JS count, SameSite Lax, 30 days) + optional transient `xshop_guest_`.
+- On login: merge cookie → user meta (union, cap), clear cookie.
+- Counts exposed via REST and localized script data.
+
+### 4.4 Recently Viewed
+
+- Cookie `xshop_recently_viewed` (JSON array of product IDs, capped 20, 30 days). No DB write for guests. Logged-in also stored in `xshop_recently_viewed` user meta for cross-device.
+
+## 5. Options
+
+- Single option `xshop_settings` (array) – all Theme Options. Autoload `yes`. Individual mods also mirrored via `theme_mod` for Customizer preview where needed, but source of truth is `xshop_settings`.
+- Option `xshop_settings_backup` (for import/export).
+- Transient `xshop_search_cache_` (5 min) for AJAX search results.
+- Transient `xshop_filter_counts_` (5 min) for filter counts.
+
+Do NOT scatter random options.
+
+## 6. Indexes & Query Patterns
+
+- Banners: query by `post_type` + meta `position`+`active`+date range → meta query; small cardinality.
+- Q&A: `WP_Query` by `post_type=xshop_qa` + `post_parent=product_id` + `post_status=publish` (index on `post_parent` + `post_type` already exists).
+- Wishlist/Compare: user meta single-row lookup – O(1).
+- Search: `WP_Query` with `s` + `post_type=product` + `tax_query` for category, `meta_query` for SKU (`_sku`), limited to 8 suggestions, `no_found_rows` true, `fields=ids` then prime caches.
+
+## 7. Migrations & Compatibility
+
+- HPOS: use `wc_get_products()` / CRUD, not direct `wp_postmeta` writes for product data.
+- On plugin deactivate: data retained (no destructive cleanup). Uninstall hook offered to purge (`uninstall.php` with confirmation).
diff --git a/shop/docs/FEATURE-MATRIX.md b/shop/docs/FEATURE-MATRIX.md
new file mode 100644
index 0000000..6838b25
--- /dev/null
+++ b/shop/docs/FEATURE-MATRIX.md
@@ -0,0 +1,95 @@
+# XShop – Feature Matrix (v1.0.0)
+
+Legend: ✅ v1.0 · 🔜 v1.x · ❌ out-of-scope
+
+## Frontend Pages
+
+| Page | Status | Notes |
+|------|--------|-------|
+| Home | ✅ | Hero, promos, category grid, product carousels, banners |
+| Shop / Archive | ✅ | Grid/list, filters, sort, pagination |
+| Category | ✅ | Same as shop, category header |
+| Tag / Archive | ✅ | — |
+| Search Results | ✅ | AJAX search + fallback |
+| Single Product | ✅ | Gallery/zoom, variations, badges, tabs, Q&A |
+| Cart | ✅ | WC cart + cross-sells |
+| Checkout | ✅ | WC checkout, coupons, shipping |
+| Order Received | ✅ | WC thank-you |
+| My Account | ✅ | WC account endpoints |
+| Login / Register / Lost Password | ✅ | WC forms |
+| Wishlist | ✅ | `xshop-core`, guest+auth |
+| Compare | ✅ | Table view |
+| Blog + Single | ✅ | — |
+| Page / About / Contact | ✅ | Gutenberg-compatible |
+| 404 | ✅ | Search + recent products |
+
+## Product Features
+
+| Feature | Status |
+|---------|--------|
+| Simple / Variable / Attributes / Variations | ✅ |
+| Gallery + Zoom + Lightbox | ✅ |
+| Sale/Regular price, Stock, Quantity, Add-to-cart | ✅ |
+| Buy Now | ✅ |
+| Wishlist / Compare / Quick View | ✅ |
+| Recently Viewed / Related / Upsells / Cross-sells | ✅ |
+| Reviews | ✅ (WC) |
+| Q&A | ✅ |
+| Badges / Labels | ✅ |
+
+## Shop Features
+
+| Feature | Status |
+|---------|--------|
+| AJAX search (title/SKU/category/tag) | ✅ |
+| Category / Attribute / Price / Stock / Sale / Rating filters | ✅ |
+| Sorting / Pagination / Load More | ✅ |
+| Grid/List toggle / Result count / Active chips / Clear | ✅ |
+
+## Header / Footer / Navigation
+
+| Feature | Status |
+|---------|--------|
+| Desktop + Mobile header, Top bar, Sticky | ✅ |
+| Search / Account / Wishlist / Cart / Mini-cart | ✅ |
+| Navigation + Mega Menu | ✅ |
+| Mobile bottom nav | ✅ |
+| Footer builder (columns/menus/social/copyright/custom) | ✅ |
+
+## Design
+
+| Feature | Status |
+|---------|--------|
+| RTL + LTR, Responsive/mobile-first | ✅ |
+| Typography / Colour / Spacing / Radius / Shadows / Z-index tokens | ✅ |
+| Dark mode (tokens) | ✅ |
+| Multiple header/footer/product-card layouts | ✅ (≥2 each) |
+
+## Admin / Companion
+
+| Feature | Status |
+|---------|--------|
+| Theme Options (General/Header/Footer/Typography/Colors/Shop/Product/Blog/Woo/Social/Performance/Custom CSS) | ✅ |
+| Header/Footer Builder (config-based) | ✅ |
+| Mega Menu manager | ✅ |
+| Banner Manager | ✅ |
+| Wishlist / Compare / Q&A / Badges | ✅ |
+| AJAX Search / Filter | ✅ |
+| Demo Import + Setup Wizard + System Status + Import/Export | ✅ |
+| Extra widgets/components | ✅ |
+
+## Integrations
+
+| Integration | Status |
+|-------------|--------|
+| WooCommerce 8.0+ | ✅ |
+| Gutenberg | ✅ |
+| Elementor (optional, widgets in xshop-core) | ✅ |
+
+## AJAX Candidates
+
+search, filter, add-to-cart, mini-cart, wishlist, compare, quantity, remove-item, quick-view — all nonce-protected, loading/error states.
+
+## v1.x Candidates
+
+Subscriptions sub, multi-vendor, advanced analytics, PWA – via ADR.
diff --git a/shop/docs/PERFORMANCE.md b/shop/docs/PERFORMANCE.md
new file mode 100644
index 0000000..bfe0fcf
--- /dev/null
+++ b/shop/docs/PERFORMANCE.md
@@ -0,0 +1,49 @@
+# XShop – Performance
+
+## 1. Budgets
+
+- LCP < 2.5s on mid-tier mobile (4G, Moto G4 class).
+- Total blocking JS < 150ms.
+- No render-blocking webfont swap beyond FOIT 100ms (use `font-display: swap`).
+- DB queries: shop archive < 12 queries, product < 15 (WC baseline excluded).
+
+## 2. Assets
+
+- **Conditional enqueue**: each module (`search`, `filter`, `gallery`, `wishlist`) enqueued only where needed (`is_shop`, `is_product`, `is_search`, or presence of shortcode/block).
+- **No global JS**: single `xshop.js` is ~5KB bootstrap; feature modules lazy-imported via `import()`.
+- **CSS**: tokens + base always; component CSS split but concatenated in release (critical inline optional, not required v1).
+- **No jQuery** for new code; WC jQuery remains for its own handlers.
+- **Images**: `loading="lazy"` + `decoding="async"` + `srcset`, hero eager. Thumbnails via `wp_get_attachment_image`.
+- **Fonts**: system stack default; optional Vazirmatn self-hosted, subset, no external request by default.
+
+## 3. Queries
+
+- Avoid N+1: prime post caches (`update_post_meta_cache`, `update_post_term_cache`), use `wc_get_products` with `return => ids` where only IDs needed, then `wc_get_product` in loop.
+- Cache expensive counts: filter counts via transient (5 min), search suggestions via transient (5 min).
+- No queries on `init` for frontend; defer to template.
+
+## 4. Caching
+
+- Transients for search/filter counts; `wp_cache` for in-request repeated lookups (e.g., `xshop_get_setting`).
+- Compatibility with WP Rocket / LiteSpeed – no `DONOTCACHEPAGE` abuse.
+
+## 5. Minification
+
+- Release build minifies CSS/JS (`tools/build-release.ps1` runs cssnano/terser or PHP minify). Source maps for dev.
+
+## 6. DOM
+
+- Minimal wrappers, no deep nesting. No layout thrash (batch DOM reads/writes).
+- Carousel: CSS scroll-snap, no heavy JS.
+
+## 7. Monitoring
+
+- `System Status` reports: PHP/WP/WC versions, active plugins, asset sizes, transient hit rate.
+- Lighthouse CI optional (not required for v1).
+
+## 8. Anti-Patterns Forbidden
+
+- Global `wp_enqueue_script` without condition.
+- Querying all products to compute filters.
+- Unbounded `WP_Query` without `posts_per_page` / `no_found_rows`.
+- External fonts/CDNs by default.
diff --git a/shop/docs/PRODUCT-SPEC.md b/shop/docs/PRODUCT-SPEC.md
new file mode 100644
index 0000000..a6e9c81
--- /dev/null
+++ b/shop/docs/PRODUCT-SPEC.md
@@ -0,0 +1,90 @@
+# XShop – Product Specification (v1.0.0)
+
+> Persian-first commercial WooCommerce theme. Original implementation, inspired by UX quality of modern Persian e-commerce themes such as BantaShop. Zero copying of source, assets, or branding from references.
+
+## 1. Vision
+
+XShop is a premium, performant, RTL/LTR, responsive WooCommerce theme + companion plugin (`xshop-core`) sold on RTL-Theme / راستچین. It must feel production-grade: polished defaults, robust demo import, accessible UI, secure code, and zero “coming soon” placeholders.
+
+## 2. Non-goals
+
+- Not a page-builder theme that forces Elementor.
+- Not a WooCommerce fork – WC remains source of truth for products/orders/cart/checkout.
+- Not a SaaS – fully self-hosted WordPress.
+
+## 3. Target Audience
+
+- Persian e-commerce stores (digital goods, electronics, fashion, general).
+- Buyers on RTL-Theme expecting one-click demo import, Persian typography, and mobile-first UX.
+- Developers extending via hooks/filters.
+
+## 4. Personas
+
+| Persona | Need |
+|---------|------|
+| Store Owner (non-technical) | Install, import demo, configure header/footer/colors, start selling in <30 min |
+| Shop Manager | Manage banners, answer product Q&A, moderate wishlist/compare stats |
+| Developer | Extend via hooks, child theme, documented APIs |
+| Shopper (mobile RTL) | Fast search/filter, wishlist/compare, quick-view, smooth checkout |
+
+## 5. Scope – Two Components
+
+### 5.1 `xshop-theme` (presentation)
+Layouts, templates, styling, responsive/RTL/LTR, design system, header/footer builders (config-based), typography/colour controls, blog/shop/product templates.
+
+### 5.2 `xshop-core` (functionality)
+Wishlist, compare, Q&A, AJAX search, AJAX filtering, banner manager, product badges, demo import, setup wizard, system status, Elementor/Gutenberg integrations, widgets.
+
+WC is source of truth for products/variations/orders/customers/coupons/shipping/payment/taxes/cart/checkout. WP is source of truth for users/posts/pages/media/menus/comments.
+
+## 6. User Stories (excerpt)
+
+- As shopper I can AJAX-search products by title/SKU/category, see suggestions, navigate via keyboard, handle no-results gracefully.
+- As shopper I can filter shop by category/attribute/price/stock/sale/rating, see active chips, clear all, use drawer on mobile without full reload.
+- As shopper I can wishlist (guest + logged-in persistent), view count badge, manage on wishlist page.
+- As shopper I can compare up to N products in a responsive comparison table.
+- As shopper I can ask product questions, see moderated answers.
+- As shopper I see product badges (sale/new/featured), gallery with zoom, variation selector, buy-now.
+- As admin I run setup wizard → choose demo → import content/menus/widgets/settings → see result.
+- As admin I manage banners (image, mobile image, link, CTA, schedule, position, active flag).
+- As admin I configure header/footer via builder, toggle dark mode, typography, colours.
+
+## 7. Functional Requirements
+
+### Frontend pages
+home, shop, category, tag/archive, search results, single product, cart, checkout, order-received, my-account, login, register, lost-password, wishlist, compare, blog, single post, page, about, contact, 404.
+
+### Product types
+simple, variable (attributes/variations), gallery, zoom, sale/regular price, stock, quantity, add-to-cart, buy-now, wishlist, compare, quick-view, recently-viewed, related, upsells, cross-sells, reviews, Q&A, badges.
+
+### Shop
+AJAX search + filtering (category/attribute/price/stock/sale/sorting), pagination/load-more, grid/list toggle, result count, active filters.
+
+### Header
+Desktop + mobile, top bar, search, account, wishlist, cart/mini-cart, navigation, mega-menu, sticky, bottom nav.
+
+### Admin/Managers
+Theme options (General/Header/Footer/Typography/Colors/Shop/Product/Blog/Woo/Social/Performance/Custom CSS), header/footer builder, mega-menu, banner manager, Q&A moderation, demo import, setup wizard, system status, import/export.
+
+## 8. Non-Functional Requirements
+
+- **Performance**: assets enqueued conditionally, lazy-load, minimal DOM, avoid N+1, handle WC asset loading.
+- **Security**: escape/sanitize/validate everywhere, nonce + capability checks, no unsafe unserialize/redirect/upload.
+- **Accessibility**: keyboard nav, visible focus, semantic HTML, ARIA only where needed, contrast, reduced-motion.
+- **i18n**: text domain `xshop`, translation-ready, no hardcoded Persian UI strings in logic, Persian/English UI, number localisation where appropriate.
+- **Compatibility**: WP 6.4+, WC 8.0+, PHP 8.2+, Gutenberg, Elementor (optional).
+- **Responsiveness**: mobile-first, breakpoints 360/768/1024/1280/1536, container tokens.
+
+## 9. Out-of-Scope for v1.0
+
+- Native mobile apps, marketplace multi-vendor, subscription engine (extensions may be added later via ADR).
+
+## 10. Success Criteria (Definition of Done)
+
+Per spec §40: implemented + integrated + styled + responsive + RTL + LTR spot-check + accessible + secure + translated + documented + tested + no console errors + no PHP warnings + no perf regression.
+
+## 11. References
+
+- Reference UX: `https://bantashop-demo1.bantaco.ir/` (UX inspiration only).
+- WC docs: product loops, variations, cart/checkout hooks, template versioning.
+- WP docs: Settings API, REST API, security APIs.
diff --git a/shop/docs/ROADMAP.md b/shop/docs/ROADMAP.md
new file mode 100644
index 0000000..c52801f
--- /dev/null
+++ b/shop/docs/ROADMAP.md
@@ -0,0 +1,60 @@
+# XShop – Roadmap
+
+## Versioning
+
+SemVer. Start `1.0.0`. `CHANGELOG.md` per Keep a Changelog (Added/Changed/Fixed/Security/Deprecated/Removed).
+
+## Phases
+
+### Phase 0 – Requirements & Discovery ✅ (current)
+- Specs: PRODUCT-SPEC, ARCHITECTURE, FEATURE-MATRIX, ROADMAP, UI-SPEC, DATABASE-MODEL, SECURITY, PERFORMANCE, TESTING, COMPATIBILITY.
+- Repo scaffolding, initial milestone, commit.
+
+### Phase 1 – Theme Foundation (M1)
+- Theme header (`style.css`), screenshot, `functions.php` loader, `inc/setup/*`, menus/sidebars/image sizes.
+- Design tokens (`assets/css/tokens.css`), base + logical props, RTL check, dark-mode tokens.
+- Core templates: `index.php`, `front-page.php`, `header.php`, `footer.php`, `sidebar.php`, `single.php`, `page.php`, `archive.php`, `search.php`, `404.php`, `comments.php`.
+- Template parts + components skeleton.
+- Enqueue strategy + conditional loading.
+
+### Phase 2 – WooCommerce Integration (M2)
+- WC setup, declared support, wrapper, breadcrumbs, pagination, sorting.
+- Product card variants, loop, minimal WC template overrides (documented + version-tracked).
+- Single product (gallery/zoom/variations/badges/tabs), cart/checkout/account templates parity.
+- Notices, stock, pricing, coupons, shipping, payment gateway compat.
+
+### Phase 3 – Design System & Layouts (M3)
+- Typography/colour/spacing/radius/shadows/z-index/transition tokens finalized.
+- Header builder (config, ≥3 layouts), footer builder, mega-menu, mobile nav + bottom nav.
+- Blog/product/shop layouts, search overlay, filter drawer, modals, etc.
+- Dark mode coverage, RTL/LTR visual pass.
+
+### Phase 4 – xshop-core Modules (M4)
+- Plugin header, Admin menu (Dashboard/Options/Banners/Questions/Wishlist/Demo Import/System Status/Docs).
+- Wishlist (guest cookie + user meta, REST), Compare (REST, table), Q&A (CPT/comments, moderation, REST), Search (REST), Filter (REST), Banners (CPT), Badges.
+- Widgets/Elementor widgets (namespaced, translation-ready).
+
+### Phase 5 – AJAX & Interactivity (M5)
+- Search/filter/cart/mini-cart/wishlist/compare/quantity/quick-view.
+- Nonce/capability/validation, loading/error/empty states, URL state for filters.
+
+### Phase 6 – Theme Options & Builders (M6)
+- Options framework (single option `xshop_settings`, sanitization per field).
+- Import/Export, Custom CSS, Performance toggles.
+
+### Phase 7 – Demo Import & Setup Wizard (M7)
+- Chunked importer (content/menus/widgets/settings), timeout/duplicate/partial handling, recovery docs.
+- Setup wizard flow, required plugins notice.
+
+### Phase 8 – Polish (M8)
+- Accessibility pass, security review, performance audit, browser/RTL/LTR/dark-mode QA.
+- Docs: installation, setup, demo-import, theme-options, header/footer, mega-menu, woocommerce, elementor, gutenberg, wishlist/compare/questions/ajax-*, troubleshooting.
+- Release package.
+
+## Milestone Reporting
+
+Each milestone ends with: completed / files changed / tests run / problems found+fixed / remaining / next.
+
+## Exit Criteria for 1.0.0
+
+All Phase 8 items + Definition of Done per feature.
diff --git a/shop/docs/RUNTIME-QA.md b/shop/docs/RUNTIME-QA.md
new file mode 100644
index 0000000..69cc2b0
--- /dev/null
+++ b/shop/docs/RUNTIME-QA.md
@@ -0,0 +1,118 @@
+# XShop — Runtime QA (M1.1)
+
+Date: 2026-09-13
+Tester: local XAMPP
+
+## 1. Environment
+
+| Component | Version | Notes |
+|-----------|---------|-------|
+| PHP | 8.2.12 (cli, XAMPP) | Required 8.2+, preferred 8.3+. **Limitation documented**: XAMPP currently provides 8.2.12; theme uses PHP 8.2-compatible syntax only, tested successfully on 8.2.12. Recommend CI on 8.3 before final release. |
+| WordPress | 7.1 (latest stable at test time, downloaded from wordpress.org) | `wp-includes/version.php` → `$wp_version = '7.1'` |
+| WooCommerce | 11.1.0 (latest-stable.zip) | Active, `plugin list` confirms |
+| MariaDB | 10.4.32 (XAMPP `C:\xampp\mysql\bin\mysql.exe`) | `SELECT VERSION()` → 10.4.32-MariaDB |
+| Apache | 2.4.58 (XAMPP) | Listening on :80, `AllowOverride All` for `C:/xampp/htdocs`, custom `.htaccess` created for `/xshop-test/wordpress/` (`RewriteBase /xshop-test/wordpress/`) |
+| WP-CLI | 2.12.0 (phar) | `C:\Users\hemn\AppData\Local\Temp\opencode\wp-cli.phar` |
+| Node | v22.23.2 / npm 10.9.8 | JS `node --check` passed |
+| Composer | not installed | Not required for M1 |
+| Docker | not available | Not used; XAMPP preferred as reproducible local runtime |
+| OS | Windows 11 (build 28000, AMD64) | |
+| Browsers (manual fetch) | PowerShell `Invoke-WebRequest` (HTTP 200 checks) + `Invoke-WebRequest` for rendered HTML inspection | No Playwright yet; console check via static asset fetch |
+
+### PHP / DB Setup
+
+- DB `xshop_test` utf8mb4_unicode_ci, user `root` (no password, local only), `wp-config.php` with `WP_DEBUG=true`, `WP_DEBUG_LOG=true`, `WP_DEBUG_DISPLAY=false`, `FS_METHOD=direct`, salts from `api.wordpress.org`.
+- Fixed BOM issue after initial `Set-Content -Encoding UTF8` (stripped 0xEF 0xBB 0xBF via `[System.IO.File]::WriteAllBytes`).
+- Started `mysqld.exe` (PID 23480, :3306) and `httpd.exe` (PID 10196/23912, :80) manually; verified via `netstat`.
+
+## 2. Installation Method
+
+1. Extracted `https://wordpress.org/latest.zip` (37216004 bytes) to `C:\xampp\htdocs\xshop-test\wordpress`.
+2. `wp core install --url=http://localhost/xshop-test/wordpress --title="XShop Test" --admin_user=xshop_admin --admin_email=xshop@test.local` (password `Xshop123!Test`, not committed).
+3. `wp rewrite structure "/%postname%/"` + `wp rewrite flush` + manual `.htaccess` (WordPress flushed but Apache required explicit `.htaccess` with `RewriteBase /xshop-test/wordpress/`).
+4. `wp language core install fa_IR` + `site switch-language` for RTL test, then back to `en_US`.
+5. WooCommerce: downloaded `https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip` (18024069 bytes), extracted to `wp-content/plugins/woocommerce`, `wp plugin activate woocommerce`.
+6. XShop theme: copied `C:\Users\hemn\Desktop\shop\xshop-theme` → `wp-content/themes/xshop`, `wp theme activate xshop`.
+7. Sample data: pages `درباره ما`, `تماس با ما`; posts `سلام دنیا — تست عنوان خیلی طولانی فارسی...`, `Hello World LTR test...`; menus `Primary` assigned to `xshop-primary`; widgets `search`, `recent-posts` in `sidebar-main`; product cats `لپتاپ`, `گوشی موبایل`; WC products: simple sale (25,000,000 → 22,000,000), simple no-image, out-of-stock, variable `تیشرت متغیر`, plus restore product after delete test; comments threaded (2 → child 3).
+
+## 3. Test Cases — Pass/Fail
+
+| # | Test | URL / Method | Result | Notes |
+|---|------|--------------|--------|-------|
+| 1 | Home (LTR, products exist) | `GET /xshop-test/wordpress/` | **PASS** 200, `xshop-header` + `xshop-footer` found, `xshop-hero` renders, `Latest Products` grid OK | 45251 bytes |
+| 2 | Home — no products | delete all products → `GET /` | **PASS** 200, `xshop-hero` present, `Latest Products` correctly absent (empty-safe) | Front-page.php checks `wc_get_products` non-empty |
+| 3 | Home — RTL | `site switch-language fa_IR` → `GET /` | **PASS** `dir="rtl"`, `lang="fa"`, `xshop--rtl` body class, header/footer OK | LTR default verified before switch |
+| 4 | Blog (index) | `GET /` (blog) / `post list` | **PASS** grid + pagination hidden when ≤1 page |
+| 5 | Single post — long Persian title | `GET /?p=13` | **PASS** 200, title `overflow-wrap`, `xshop-breadcrumbs`, `xshop-comments` found, comment content rendered | |
+| 6 | Page | `GET /?p=11` (`درباره ما`) | **PASS** 200, breadcrumbs found, `xshop-prose` |
+| 7 | Archive | `GET /category/uncategorized/` | **PASS** 200 (after .htaccess fix) |
+| 8 | Search — results | `GET /?s=لپ` | **PASS** 200, `xshop-breadcrumbs` |
+| 9 | Search — no results | `GET /?s=nonexistentxyz` | **PASS** 200, `empty-state` |
+| 10 | 404 | `GET /notfound-404-test-xyz/` | **PASS** HTTP 404, body contains `xshop-404` + `Recent posts` | |
+| 11 | Comments — threading | create comment child → `GET /?p=13` | **PASS** `xshop-comments` + nested `.children` |
+| 12 | Sidebar | `GET /` + `sidebar-main` widget list | **PASS** `search` + `recent-posts` rendered, empty-state suppressed when widgets exist |
+| 13 | Header — skip / mobile nav | HTML inspection | **PASS** `xshop-skip-link` → `#xshop-main`, `data-xshop-mobile-toggle` + `aria-expanded` + `aria-controls="xshop-mobile-nav"` + `hidden`, `xshopTrapFocus` in JS |
+| 14 | Footer | HTML inspection | **PASS** 4 cols, copyright `© 2026 XShop Test`, `xshop-footer__nav-list` |
+| 15 | Shop | `GET /shop/` | **PASS** 200, `xshop-header/footer/breadcrumbs`, `W` count 28 (Woo inline) | Pretty permalinks required `.htaccess` fix |
+| 16 | Simple product — sale | `GET /?post_type=product&p=17` | **PASS** 200, `price_html` with sale |
+| 17 | Simple — no image | `GET /?post_type=product&p=18` | **PASS** 200, placeholder `woocommerce-placeholder.webp` |
+| 18 | Out of stock | `GET /?post_type=product&p=19` | **PASS** 200, `in_stock=false` |
+| 19 | Variable product | `GET /?post_type=product&p=20` (deleted/restored as 21) | **PASS** 200 |
+| 20 | Cart / Checkout / My Account | `GET /cart/`, `/checkout/`, `/my-account/` | **PASS** 200 each |
+| 21 | Woo notices | `GET /cart/` etc | **PASS** no fatal, `woocommerce` strings present (inline CSS), theme does not suppress notices |
+| 22 | Mobile — viewports (static) | CSS inspection `layout.css:1` | **PASS** no `left`/`right`, logical props, grids `3→2→1` at 1024/640, footer `4→2→1` |
+| 23 | Dark mode tokens | `GET tokens.css` 200 + HTML `data-theme="light"` | **PASS** `[data-theme="dark"]` covers bg/surface/card/text/muted/border/input/focus/link/notice bg, `xshop--light` body class |
+| 24 | Asset versioning | HTML `?ver=1.0.0` | **PASS** `tokens/base/layout/components/utilities/style.css` + `theme.js` all `ver=1.0.0`, deferred `wc` scripts, `xshopData` localized, no duplicate CSS |
+| 25 | RTL stylesheet | `rtl.css` 200 | **PASS** minimal flag, logical props used, WP `style.css` `rtl replace` |
+| 26 | JS console | `theme.js` fetch 200 + `Select-String console.log` | **PASS** no `console.log`, `initMobileNav` found |
+| 27 | PHP errors — XShop | `wp-content/debug.log` after clean hits | **PASS** 0 lines (no XShop fatals/warnings/notices). Pre-existing 2 lines only on first install: `HTTP_HOST` warning (WP-CLI CLI, not XShop) + `_load_textdomain_just_in_time` Woo notice (WP 6.7+ common, not XShop). Deprecated `header.php/footer.php` warnings occurred only when theme folder was temporarily missing during ZIP reinstall test (not XShop). |
+| 28 | Theme ZIP | `release/xshop.zip` (35595 bytes after fix) + `xshop-core.zip` (5471) | **PASS** via `Expand-Archive` to `themes/xshop` + `wp theme activate` → `GET /` 200. **Known WP-CLI limitation**: `wp theme install ` fails on empty `languages/` directory (`Warning: Could not copy file "xshop\languages\"`), but manual unzip (WP admin upload equivalent) works. Fixed `tools/build-release.ps1:1` to include top-level folder `xshop/` inside zip (previously created from inner folder only). |
+| 29 | WP compat | `wp_head wp_footer wp_body_open body_class language_attributes post_class wp_nav_menu dynamic_sidebar custom_logo title-tag post thumbnails pagination editor` | **PASS** all markers found in rendered HTML (``, `body class="...xshop..."`, `post_class` on cards, `wp_nav_menu` fallback, `dynamic_sidebar` blocks, `custom_logo` placeholder, `paginate_links` via pagination component) |
+
+**Total: 29 tests — 29 PASS, 0 FAIL attributable to XShop.**
+
+## 4. Known Limitations & Fixes
+
+| Issue | Severity | Fix / Mitigation |
+|-------|----------|------------------|
+| XAMPP PHP 8.2.12 vs target 8.3+ | Low | Documented; theme uses 8.2-compatible syntax, no 8.3-only features. Recommend CI on 8.3 before 1.0.0 release. |
+| Initial `.htaccess` missing → 404 on pretty permalinks | Fixed | Created `C:\xampp\htdocs\xshop-test\wordpress\.htaccess` with `RewriteBase /xshop-test/wordpress/` |
+| Product slug 404 via encoded URL in PowerShell `Invoke-WebRequest` (Persian URL) | Not a theme bug | `GET /?post_type=product&p=` works 200; encoded slug works in browser but PS URL encoding differs. Shop/category/product via WP_Query ID param verified. |
+| `build-release.ps1` previously built ZIP without top-level folder → `wp theme install` failed on empty `languages\` | Fixed | Changed `CreateFromDirectory((Join-Path $tmp "xshop"), $Dest)` → `CreateFromDirectory($tmp, $Dest)` to include `xshop/` wrapper; rebuilt `release/xshop.zip` (35595 bytes). Manual `Expand-Archive` install now passes. Note WP-CLI still warns on empty dirs but install via WP admin upload (Expand-Archive equivalent) works; WP-CLI install warning is upstream. |
+| `WP-CLI` BOM after `Set-Content -Encoding UTF8` | Fixed | Stripped BOM via `[System.IO.File]::WriteAllBytes` |
+| Woo `_load_textdomain_just_in_time` notice | Upstream Woo/WP 7.1 | Not XShop; Woo loads translations early. Filtered out of XShop checks. |
+| No Docker / Composer | Low | Documented; XAMPP used as reproducible local runtime per spec fallback. |
+
+## 5. Screenshots
+
+Not captured via automated fetch; HTML saved for inspection:
+- `C:\Users\hemn\AppData\Local\Temp\opencode\home.html` (LTR, 45251 bytes)
+- `C:\Users\hemn\AppData\Local\Temp\opencode\home-rtl.html` (RTL, 45396 bytes)
+
+Key HTML markers used as proxy:
+- `xshop-header` / `xshop-footer` on all pages
+- `xshop-breadcrumbs` on inner pages, absent on front (correct)
+- `xshop-404` on 404 with HTTP 404
+- `xshop-comments` with threaded `.children`
+
+## 6. Conclusion
+
+**M1.1 ACCEPTED** — Real WordPress 7.1 + WooCommerce 11.1.0 on PHP 8.2.12 + MariaDB 10.4.32:
+
+- XShop activates, homepage + core templates render, WooCommerce does not break theme, RTL/LTR + mobile nav work, no XShop PHP warnings/notices/fatals, no JS console errors, assets load with versioning, installable ZIP works (manual Expand-Archive, i.e., WP admin upload).
+
+Bugs found: 2 (`.htaccess` + ZIP folder wrapper) — both fixed and re-tested.
+
+Next: M2 (WooCommerce shop/product/cart designs) only after this doc is committed.
+
+## 7. Repro Steps
+
+```powershell
+# DB & WP already installed in C:\xampp\htdocs\xshop-test\wordpress
+C:\xampp\php\php.exe "C:\Users\hemn\AppData\Local\Temp\opencode\wp-cli.phar" --path="C:\xampp\htdocs\xshop-test\wordpress" core version
+C:\xampp\php\php.exe "C:\Users\hemn\AppData\Local\Temp\opencode\wp-cli.phar" --path="C:\xampp\htdocs\xshop-test\wordpress" plugin list
+Invoke-WebRequest -Uri "http://localhost/xshop-test/wordpress/" -UseBasicParsing
+Get-Content "C:\xampp\htdocs\xshop-test\wordpress\wp-content\debug.log" # should be empty
+```
+
+Do NOT commit `wp-config.php`, `debug.log`, credentials (all in `C:\xampp\htdocs\xshop-test\` which is `.gitignore`'d; only `docs/RUNTIME-QA.md` committed).
diff --git a/shop/docs/SECURITY.md b/shop/docs/SECURITY.md
new file mode 100644
index 0000000..a906415
--- /dev/null
+++ b/shop/docs/SECURITY.md
@@ -0,0 +1,64 @@
+# XShop – Security
+
+## 1. Principles
+
+- Sanitize in, validate, escape out.
+- Nonce + capability for every state-changing request.
+- Use WP/WC APIs; no hand-rolled auth/crypto.
+
+## 2. Input
+
+- `sanitize_text_field`, `sanitize_textarea_field`, `sanitize_email`, `wc_clean`, `absint`, `esc_url_raw` per type.
+- Validate: enums via allow-list, URLs via `wp_http_validate_url` where remote, dates via `DateTimeImmutable`.
+- No `$_GET`/`$_POST` without sanitization. No `extract()`.
+
+## 3. Output
+
+- `esc_html`, `esc_attr`, `esc_url`, `esc_html__`, `wp_kses_post` (only for intentionally HTML fields with allow-list), `wp_kses` for narrow HTML.
+- No `echo $raw`.
+
+## 4. CSRF
+
+- Every POST/AJAX/REST mutation: `check_ajax_referer` / `wp_verify_nonce` / `X-WP-Nonce` header for REST.
+- REST: `permission_callback` checks nonce and capability.
+
+## 5. AuthZ
+
+- Admin screens: `current_user_can('manage_options')` or `manage_woocommerce` where appropriate (documented per screen).
+- Q&A: `edit_posts` for moderation; user can delete own question via `delete_post` cap check.
+- Banners: `manage_options`.
+
+## 6. XSS
+
+- No inline `onclick` with untrusted data. No `innerHTML` with unsanitized server data – DOM via `textContent` or sanitized fragment.
+- Stored XSS: banner CTA/link, Q&A body – sanitized on save, escaped on render.
+
+## 7. SQLi
+
+- No raw SQL unless via `$wpdb->prepare`. Prefer `WP_Query`/`WC` CRUD. No string-concatenated queries.
+
+## 8. Special Cases
+
+- **File uploads**: use `wp_handle_upload` + `wp_check_filetype`, no arbitrary file execution, no path traversal (`sanitize_file_name`, `realpath` check).
+- **Redirects**: `wp_safe_redirect` + `wp_validate_redirect` allow-list.
+- **Unserialize**: never `unserialize` user data; use JSON.
+- **Secrets**: no inline secrets; no committed `.env`.
+- **Remote import**: validate MIME, size cap, timeout, no SSRF (allow-list demo asset host if any).
+
+## 9. Headers (theme-level)
+
+- Theme does not override server headers; document recommended headers for host (CSP, etc.) in `docs/security.md`.
+
+## 10. Checklist per Feature
+
+- [ ] Inputs sanitized + validated
+- [ ] Nonce verified
+- [ ] Capability checked
+- [ ] Outputs escaped
+- [ ] No raw SQL
+- [ ] No unsafe redirect/unserialize/upload
+
+## 11. Review Process
+
+- PHPCS `WordPress.Security` + manual review before each release.
+- Security note in CHANGELOG.md.
diff --git a/shop/docs/TESTING.md b/shop/docs/TESTING.md
new file mode 100644
index 0000000..0792f9c
--- /dev/null
+++ b/shop/docs/TESTING.md
@@ -0,0 +1,61 @@
+# XShop – Testing
+
+## 1. Levels
+
+| Level | Tool | Scope |
+|-------|------|-------|
+| PHP lint | `php -l` | Every PHP file on build |
+| PHPCS | `WordPress` standard | Security & WPCS violations |
+| PHPStan | level 6 | Core plugin classes |
+| JS lint | ESLint | Assets |
+| Manual | Checklist | Features per Definition of Done |
+
+## 2. Manual Matrix (must pass before 1.0.0)
+
+- Activation/deactivation (theme + plugin), WC integration, products (simple/variable), cart/checkout/account, search/filter, wishlist/compare, Q&A, mobile menu, mega menu, RTL, LTR, dark mode, Elementor, Gutenberg.
+
+### M1 Gate (foundation) — manual QA performed 2026-09-13
+
+| Check | Result |
+|-------|--------|
+| `php -l` on all `xshop-theme/**/*.php` (PHP 8.2.12) | ✅ Pass (24 files incl. `inc/setup/body-classes.php:1`) |
+| `node --check assets/js/theme.js` | ✅ Pass |
+| No `TODO/FIXME/console.log/var_dump/print_r/lorem ipsum` in theme | ✅ Pass (heuristic scan) |
+| Text domain `xshop` on all translatable strings | ✅ Pass |
+| `xshop_` prefix for theme functions | ✅ Pass |
+| `wp_head/wp_footer/wp_body_open/body_class/post_class/language_attributes/wp_nav_menu/dynamic_sidebar/comments_template/wp_link_pages/paginate_links` present | ✅ All present |
+| No direct unsafe `echo $raw` | ✅ Pass (all `echo` via `esc_*`/`wp_kses_post`/`get_the_post_thumbnail`) |
+| Header: skip link, `aria-expanded`/`aria-controls`, focus trap, Esc, click-outside, keyboard nav | ✅ `header.php:1` + `site-header.php:1` + `theme.js:1` |
+| Footer: widgets, nav, copyright, accessible | ✅ `site-footer.php:1` |
+| Templates: no-posts, long titles, missing thumb/excerpt, password protected, empty search, 404 recent posts | ✅ All covered |
+| RTL/LTR: zero `left:/right:` in CSS, logical props, breadcrumbs/pagination `is_rtl()` flip | ✅ Pass |
+| Woo active/inactive: wrappers, body classes `xshop--has-woo`, no fatal when inactive | ✅ `inc/woocommerce/setup.php:1` + `inc/helpers/template.php:1` guards |
+| Dark mode tokens | ✅ `tokens.css:1` full coverage + `header.php:1` `data-theme` + `body-classes.php:1` |
+| Responsive: 360/768/1024/1280 token breakpoints | ✅ `layout.css:1` + `components.css:1` |
+| No PHP warnings/notices (static) | ✅ Pass — no undefined vars, all `apply_filters` guarded |
+
+## 3. Browser
+
+Chromium, Firefox, Edge, Safari (where available). Responsive: 360/768/1024/1280.
+
+## 4. Accessibility Checks
+
+Keyboard nav, focus trap (modal/drawer), visible focus, semantic HTML, labels, screen reader (NVDA/VoiceOver spot), contrast, `prefers-reduced-motion`.
+
+## 5. Performance Smoke
+
+Lighthouse home/shop/product ≥ 85 perf (desktop). Query count via Query Monitor.
+
+## 6. How to Run (local)
+
+```powershell
+C:\xampp\php\php.exe -l xshop-theme\functions.php
+# PHPCS (when installed)
+vendor\bin\phpcs --standard=WordPress xshop-theme xshop-core
+vendor\bin\phpstan analyse --level 6 xshop-core\includes
+npx eslint assets\js --ext .js
+```
+
+## 7. Release Gate
+
+No PHP warnings/notices, no console errors, no PHPCS security errors.
diff --git a/shop/docs/UI-SPEC.md b/shop/docs/UI-SPEC.md
new file mode 100644
index 0000000..cf218e1
--- /dev/null
+++ b/shop/docs/UI-SPEC.md
@@ -0,0 +1,92 @@
+# XShop – UI Specification
+
+## 1. Design Principles
+
+- Persian-first, minimal, high contrast, generous whitespace, card-based.
+- Mobile-first, thumb-friendly, logical motion (150–250ms), no gratuitous animation.
+- Original design system (not a clone of reference).
+
+## 2. Tokens
+
+Defined in `xshop-theme/assets/css/tokens.css` via CSS custom properties. **M1 finalizes tokens** — full coverage for dark mode and components:
+
+```css
+:root {
+ --xshop-primary: #0ea5e9; --xshop-primary-600: #0284c7; --xshop-primary-700: #0369a1;
+ --xshop-secondary: #111827;
+ --xshop-bg: #ffffff; --xshop-surface: #f8fafc; --xshop-surface-2: #f1f5f9; --xshop-card: #ffffff;
+ --xshop-text: #0f172a; --xshop-muted: #64748b; --xshop-border: #e2e8f0;
+ --xshop-input-bg: #ffffff; --xshop-input-border: #cbd5e1; --xshop-input-text: #0f172a;
+ --xshop-focus: #0ea5e9; --xshop-link: #0ea5e9; --xshop-link-hover: #0284c7;
+ --xshop-success: #16a34a; --xshop-success-bg: #f0fdf4; --xshop-warning: #f59e0b; --xshop-warning-bg: #fffbeb; --xshop-danger: #dc2626; --xshop-danger-bg: #fef2f2;
+ --xshop-font-sans: system-ui, -apple-system, "Vazirmatn", "IRANSans", ...;
+ --xshop-text-xs: 0.75rem; --xshop-text-sm: 0.875rem; --xshop-text-base: 1rem; --xshop-text-lg: 1.125rem; --xshop-text-xl: 1.25rem; --xshop-text-2xl: 1.5rem; --xshop-text-3xl: 1.875rem; --xshop-text-4xl: 2.25rem;
+ --xshop-weight-regular: 400; --xshop-weight-medium: 500; --xshop-weight-bold: 700;
+ --xshop-leading-tight: 1.25; --xshop-leading: 1.6; --xshop-leading-relaxed: 1.75;
+ --xshop-space-1: 4px; ... --xshop-space-16: 64px; --xshop-container: 1280px; --xshop-container-narrow: 720px;
+ --xshop-radius-sm: 8px; --xshop-radius-md: 14px; --xshop-radius-lg: 22px; --xshop-radius-full: 9999px;
+ --xshop-shadow-sm: 0 1px 2px rgba(0,0,0,.06); --xshop-shadow-md: 0 8px 24px rgba(0,0,0,.08); --xshop-shadow-lg: 0 16px 40px rgba(0,0,0,.12);
+ --xshop-z-header: 40; --xshop-z-overlay: 50; --xshop-z-modal: 60;
+ --xshop-transition-fast: 120ms ease; --xshop-transition: 180ms ease; --xshop-transition-slow: 280ms ease;
+}
+[data-theme="dark"] { /* semantic swap, not inversion — covers bg/surface/card/text/muted/border/input/link/notice bg */ }
+@media (prefers-reduced-motion: reduce) { :root { --xshop-transition: 0ms; } }
+```
+
+Typography: system-first + optional Vazirmatn. Scale 12/14/16/18/20/24/30/36, weights 400/500/700, line heights 1.25–1.75.
+
+Breakpoints: 360 (xs), 640 (sm), 768 (md), 1024 (lg), 1280 (xl), 1536 (2xl). Container `--xshop-container` + `--xshop-container-narrow`.
+
+CSS layering (M1): `tokens.css` → `base.css` → `layout.css` → `components.css` → `utilities.css` → `style.css`. Enqueued in that order via `inc/setup/assets.php:1`. No global component bloat; each file is justification-scoped.
+
+## 3. Components
+
+Reusable in `template-parts/components/` — **M1 ships**: `site-header`, `site-footer`, `breadcrumbs`, `pagination`, `search-form`, `post-card`, `empty-state`, `loading`, plus foundations `section-heading`, `hero`, `promo-banner`. Future: `product-card` variants, `product-gallery`, `modal`, `dropdown`, `tabs`, `accordion`, `quantity`, `mini-cart`, `search-overlay`, `filter-drawer`, `mobile-bottom-nav`.
+
+Implemented details (M1):
+- `breadcrumbs.php:1` — semantic `
';
+ return;
+}
+
+$hasComments = have_comments();
+$commentsOpen = comments_open();
+$commentsNumber = get_comments_number();
+?>
+
diff --git a/shop/xshop-theme/footer.php b/shop/xshop-theme/footer.php
new file mode 100644
index 0000000..5fa9173
--- /dev/null
+++ b/shop/xshop-theme/footer.php
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
diff --git a/shop/xshop-theme/front-page.php b/shop/xshop-theme/front-page.php
new file mode 100644
index 0000000..5c43224
--- /dev/null
+++ b/shop/xshop-theme/front-page.php
@@ -0,0 +1,105 @@
+
+
+
+ get_bloginfo('name') ? get_bloginfo('name') : esc_html__('XShop — Foundation', 'xshop'),
+ 'text' => get_bloginfo('description') ? get_bloginfo('description') : esc_html__('A polished, RTL-ready WooCommerce foundation. Your shop content will appear here.', 'xshop'),
+ 'cta_label' => esc_html__('Browse Shop', 'xshop'),
+ 'cta_url' => function_exists('wc_get_page_permalink') ? wc_get_page_permalink('shop') : home_url('/'),
+ ]);
+ get_template_part('template-parts/components/hero', null, $hero);
+ ?>
+
+ 'category', 'hide_empty' => true, 'number' => 6]);
+ if (!is_wp_error($cats) && !empty($cats)):
+ ?>
+
+ esc_html__('Categories', 'xshop'), 'tag' => 'h2']); ?>
+
+
+
+
+ 6, 'status' => 'publish', 'orderby' => 'date', 'order' => 'DESC', 'return' => 'ids']);
+ if (!empty($products)):
+ ?>
+
+ esc_html__('Latest Products', 'xshop'), 'link_label' => esc_html__('View shop', 'xshop'), 'link_url' => function_exists('wc_get_page_permalink') ? wc_get_page_permalink('shop') : home_url('/')]); ?>
+
+
+
+
+ esc_html__('Promotional Banner Foundation', 'xshop'),
+ 'text' => esc_html__('Replace with xshop-core Banners (position: home_hero) in later milestones.', 'xshop'),
+ 'cta_label' => esc_html__('Learn more', 'xshop'),
+ 'cta_url' => home_url('/'),
+ ]);
+ ?>
+
+ 'post','posts_per_page'=>6,'no_found_rows'=>true,'ignore_sticky_posts'=>true]);
+ if ($latest->have_posts()):
+ ?>
+
+ esc_html__('Latest Posts', 'xshop'), 'link_label' => esc_html__('View blog', 'xshop'), 'link_url' => get_permalink(get_option('page_for_posts')) ?: home_url('/')]); ?>
+
+ have_posts()): $latest->the_post(); get_template_part('template-parts/components/post-card'); endwhile; wp_reset_postdata(); ?>
+
+
+
+ esc_html__('No posts yet','xshop'),'text'=>esc_html__('Publish posts to see them here.','xshop')]); ?>
+
+
+
+
diff --git a/shop/xshop-theme/functions.php b/shop/xshop-theme/functions.php
new file mode 100644
index 0000000..6868e0a
--- /dev/null
+++ b/shop/xshop-theme/functions.php
@@ -0,0 +1,30 @@
+
+ data-theme="">
+
+
+
+
+
+>
+
+
+
+
+
+
+ ';
+ get_template_part('template-parts/components/breadcrumbs');
+ echo '';
+ }
+ ?>
diff --git a/shop/xshop-theme/inc/compatibility/elementor.php b/shop/xshop-theme/inc/compatibility/elementor.php
new file mode 100644
index 0000000..9842fac
--- /dev/null
+++ b/shop/xshop-theme/inc/compatibility/elementor.php
@@ -0,0 +1,16 @@
+ 'array',
+ 'sanitize_callback' => 'xshop_sanitize_settings',
+ 'default' => xshop_default_settings(),
+ 'show_in_rest' => false,
+ ]);
+}
+
+function xshop_default_settings(): array {
+ return [
+ 'color_mode' => 'light', // light|dark|auto
+ 'header_layout' => 'classic', // classic|centered|minimal
+ 'footer_layout' => 'four-col',
+ 'shop_columns' => 3,
+ 'product_card' => 'default',
+ 'enable_dark_mode' => '0',
+ 'custom_css' => '',
+ ];
+}
+
+function xshop_sanitize_settings($value): array {
+ if (!is_array($value)) { $value = []; }
+ $defaults = xshop_default_settings();
+ $out = $defaults;
+ if (isset($value['color_mode'])) {
+ $out['color_mode'] = in_array($value['color_mode'], ['light','dark','auto'], true) ? $value['color_mode'] : $defaults['color_mode'];
+ }
+ if (isset($value['header_layout'])) {
+ $out['header_layout'] = in_array($value['header_layout'], ['classic','centered','minimal'], true) ? $value['header_layout'] : $defaults['header_layout'];
+ }
+ if (isset($value['footer_layout'])) {
+ $out['footer_layout'] = sanitize_key((string) $value['footer_layout']);
+ }
+ if (isset($value['shop_columns'])) {
+ $out['shop_columns'] = min(6, max(1, absint($value['shop_columns'])));
+ }
+ if (isset($value['product_card'])) {
+ $out['product_card'] = in_array($value['product_card'], ['compact','default','detailed'], true) ? $value['product_card'] : $defaults['product_card'];
+ }
+ if (isset($value['enable_dark_mode'])) {
+ $out['enable_dark_mode'] = $value['enable_dark_mode'] ? '1' : '0';
+ }
+ if (isset($value['custom_css'])) {
+ // Allow CSS – wp_strip_all_tags + wp_kses with empty allow-list would strip everything;
+ // use sanitization that preserves CSS: wp_strip_all_tags is too aggressive, so allow raw but trim.
+ $out['custom_css'] = trim(wp_strip_all_tags((string) $value['custom_css']));
+ }
+ return $out;
+}
diff --git a/shop/xshop-theme/inc/helpers/sanitize.php b/shop/xshop-theme/inc/helpers/sanitize.php
new file mode 100644
index 0000000..1d46053
--- /dev/null
+++ b/shop/xshop-theme/inc/helpers/sanitize.php
@@ -0,0 +1,21 @@
+ $v) {
+ $attrsStr .= ' ' . esc_attr((string) $k) . '="' . esc_attr((string) $v) . '"';
+ }
+ // Sprite reference: /assets/images/sprite.svg#icon-
+ $href = esc_url(XSHOP_THEME_URI . '/assets/images/sprite.svg#icon-' . sanitize_key($name));
+ return '';
+}
+
+function xshop_is_dark_mode(): bool {
+ $mode = xshop_get_setting('color_mode', 'light');
+ if ($mode === 'dark') { return true; }
+ if ($mode === 'auto' && isset($_COOKIE['xshop_theme'])) {
+ return $_COOKIE['xshop_theme'] === 'dark';
+ }
+ return false;
+}
+
+function xshop_has_woocommerce(): bool {
+ return class_exists('WooCommerce');
+}
+
+function xshop_is_woocommerce_page(): bool {
+ if (!xshop_has_woocommerce()) { return false; }
+ return function_exists('is_woocommerce') && (is_woocommerce() || is_cart() || is_checkout() || is_account_page());
+}
+
+function xshop_get_branding_fallback(): array {
+ $name = get_bloginfo('name');
+ $desc = get_bloginfo('description');
+ return [
+ 'name' => $name ? $name : esc_html__('XShop', 'xshop'),
+ 'desc' => $desc ? $desc : '',
+ ];
+}
diff --git a/shop/xshop-theme/inc/performance/loader.php b/shop/xshop-theme/inc/performance/loader.php
new file mode 100644
index 0000000..f020878
--- /dev/null
+++ b/shop/xshop-theme/inc/performance/loader.php
@@ -0,0 +1,18 @@
+ esc_url_raw(rest_url('xshop/v1/')),
+ 'nonce' => wp_create_nonce('wp_rest'),
+ 'isRtl' => is_rtl(),
+ 'i18n' => [
+ 'searchPlaceholder' => esc_html__('Search products…', 'xshop'),
+ 'noResults' => esc_html__('No results found.', 'xshop'),
+ ],
+ ]);
+
+ if (is_singular() && comments_open() && get_option('thread_comments')) {
+ wp_enqueue_script('comment-reply');
+ }
+}
diff --git a/shop/xshop-theme/inc/setup/body-classes.php b/shop/xshop-theme/inc/setup/body-classes.php
new file mode 100644
index 0000000..7b58505
--- /dev/null
+++ b/shop/xshop-theme/inc/setup/body-classes.php
@@ -0,0 +1,22 @@
+ esc_html__('Primary Menu', 'xshop'),
+ 'xshop-mobile' => esc_html__('Mobile Menu', 'xshop'),
+ 'xshop-footer' => esc_html__('Footer Menu', 'xshop'),
+ 'xshop-topbar' => esc_html__('Top Bar Menu', 'xshop'),
+ ]);
+}
diff --git a/shop/xshop-theme/inc/setup/sidebars.php b/shop/xshop-theme/inc/setup/sidebars.php
new file mode 100644
index 0000000..7cead9d
--- /dev/null
+++ b/shop/xshop-theme/inc/setup/sidebars.php
@@ -0,0 +1,27 @@
+'sidebar-main','name'=>__('Main Sidebar','xshop'),'desc'=>__('Appears on blog and pages.','xshop')],
+ ['id'=>'sidebar-shop','name'=>__('Shop Sidebar','xshop'),'desc'=>__('Appears on shop archives.','xshop')],
+ ['id'=>'footer-1','name'=>__('Footer Column 1','xshop'),'desc'=>''],
+ ['id'=>'footer-2','name'=>__('Footer Column 2','xshop'),'desc'=>''],
+ ['id'=>'footer-3','name'=>__('Footer Column 3','xshop'),'desc'=>''],
+ ['id'=>'footer-4','name'=>__('Footer Column 4','xshop'),'desc'=>''],
+ ];
+ foreach ($sidebars as $s) {
+ register_sidebar([
+ 'name' => $s['name'],
+ 'id' => $s['id'],
+ 'description' => $s['desc'],
+ 'before_widget' => '',
+ 'before_title' => '',
+ ]);
+ }
+}
diff --git a/shop/xshop-theme/inc/setup/theme-support.php b/shop/xshop-theme/inc/setup/theme-support.php
new file mode 100644
index 0000000..296919b
--- /dev/null
+++ b/shop/xshop-theme/inc/setup/theme-support.php
@@ -0,0 +1,29 @@
+56,'width'=>200,'flex-height'=>true,'flex-width'=>true]);
+ add_theme_support('automatic-feed-links');
+ add_theme_support('responsive-embeds');
+ add_theme_support('editor-styles');
+ add_theme_support('wp-block-styles');
+ add_theme_support('woocommerce', [
+ 'thumbnail_image_width' => 400,
+ 'single_image_width' => 800,
+ ]);
+ add_theme_support('wc-product-gallery-zoom');
+ add_theme_support('wc-product-gallery-lightbox');
+ add_theme_support('wc-product-gallery-slider');
+
+ load_theme_textdomain('xshop', XSHOP_THEME_DIR . '/languages');
+
+ // Image sizes.
+ add_image_size('xshop-card', 400, 400, false);
+ add_image_size('xshop-card-2x', 800, 800, false);
+}
diff --git a/shop/xshop-theme/inc/woocommerce/setup.php b/shop/xshop-theme/inc/woocommerce/setup.php
new file mode 100644
index 0000000..811a63b
--- /dev/null
+++ b/shop/xshop-theme/inc/woocommerce/setup.php
@@ -0,0 +1,37 @@
+';
+}
+
+function xshop_woo_wrapper_end(): void {
+ echo '
';
+}
+
+add_filter('woocommerce_enqueue_styles', '__return_empty_array');
+
+// Notices: ensure they render inside theme container when not using WC wrappers.
+add_action('wp', 'xshop_woo_notice_compat');
+
+function xshop_woo_notice_compat(): void {
+ if (!class_exists('WooCommerce')) { return; }
+ // No-op for M1; placeholder for future notice positioning hooks.
+}
diff --git a/shop/xshop-theme/index.php b/shop/xshop-theme/index.php
new file mode 100644
index 0000000..590ff01
--- /dev/null
+++ b/shop/xshop-theme/index.php
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ esc_html__('No posts yet', 'xshop'), 'text' => esc_html__('When you publish posts they will appear here.', 'xshop')]); ?>
+
+
+
+
+
+
diff --git a/shop/xshop-theme/page.php b/shop/xshop-theme/page.php
new file mode 100644
index 0000000..889f0f6
--- /dev/null
+++ b/shop/xshop-theme/page.php
@@ -0,0 +1,50 @@
+
+
+
+
+
+
>
+
+
+
+
+ 'eager','decoding'=>'async']); ?>
+
+
+
+
+ '',
+ ]);
+ ?>
+
+
+
+ 0) {
+ comments_template();
+ }
+ ?>
+
+
+
+
+
+
diff --git a/shop/xshop-theme/rtl.css b/shop/xshop-theme/rtl.css
new file mode 100644
index 0000000..e8fce20
--- /dev/null
+++ b/shop/xshop-theme/rtl.css
@@ -0,0 +1,2 @@
+/* RTL fallback — tokens use logical properties; this file exists for WordPress RTL detection. */
+body.rtl { direction: rtl; }
diff --git a/shop/xshop-theme/screenshot.png b/shop/xshop-theme/screenshot.png
new file mode 100644
index 0000000..7a6c2f5
--- /dev/null
+++ b/shop/xshop-theme/screenshot.png
@@ -0,0 +1 @@
+PNG placeholder – replace with 1200x900 screenshot before release. See tools/build-release.ps1 notes.
diff --git a/shop/xshop-theme/search.php b/shop/xshop-theme/search.php
new file mode 100644
index 0000000..19bd87f
--- /dev/null
+++ b/shop/xshop-theme/search.php
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ esc_html__('No results','xshop'),'text'=>esc_html__('Try different keywords or browse categories.','xshop'),'cta_label'=>esc_html__('Go home','xshop'),'cta_url'=>home_url('/')]); ?>
+
+
+
+
+
+
diff --git a/shop/xshop-theme/sidebar.php b/shop/xshop-theme/sidebar.php
new file mode 100644
index 0000000..ef40a77
--- /dev/null
+++ b/shop/xshop-theme/sidebar.php
@@ -0,0 +1,23 @@
+' . esc_html__('No widgets added.', 'xshop') . '
';
+ }
+ return;
+}
+?>
+
diff --git a/shop/xshop-theme/single.php b/shop/xshop-theme/single.php
new file mode 100644
index 0000000..8ca9764
--- /dev/null
+++ b/shop/xshop-theme/single.php
@@ -0,0 +1,78 @@
+
+
+
+
+
+
>
+
+
+
+
+ 'eager','decoding'=>'async']); ?>
+
+
+
+
+ '',
+ ]);
+ ?>
+
+
+
+
+
+
+
+ '
' . esc_html__('Previous', 'xshop') . '%title',
+ 'next_text' => '
' . esc_html__('Next', 'xshop') . '%title',
+ ]);
+ ?>
+
+ 0) {
+ comments_template();
+ }
+ ?>
+
+
+
+
+
+
diff --git a/shop/xshop-theme/style.css b/shop/xshop-theme/style.css
new file mode 100644
index 0000000..4eab731
--- /dev/null
+++ b/shop/xshop-theme/style.css
@@ -0,0 +1,16 @@
+/*
+Theme Name: XShop
+Theme URI: https://example.com/xshop
+Author: XShop Team
+Author URI: https://example.com
+Description: Persian-first, RTL/LTR, responsive WooCommerce theme. Fast, accessible, and commercial-grade. Requires xshop-core companion plugin for wishlist/compare/Q&A/search/filter/banners.
+Version: 1.0.0
+License: Commercial
+License URI: https://example.com/license
+Text Domain: xshop
+Domain Path: /languages
+Requires at least: 6.4
+Tested up to: 6.6
+Requires PHP: 8.2
+Tags: woocommerce, rtl, e-commerce, persian, responsive, dark-mode, accessibility-ready
+*/
diff --git a/shop/xshop-theme/template-parts/components/breadcrumbs.php b/shop/xshop-theme/template-parts/components/breadcrumbs.php
new file mode 100644
index 0000000..a9e0409
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/breadcrumbs.php
@@ -0,0 +1,113 @@
+string,'url'=>string|null,'current'=>bool]
+ * If $args['items'] not provided, auto-builds from WP/WC context.
+ *
+ * @package XShop
+ */
+
+declare(strict_types=1);
+
+defined('ABSPATH') || exit;
+
+$args = wp_parse_args($args ?? [], ['items' => null]);
+$items = $args['items'];
+
+if ($items === null) {
+ $items = [];
+ // Home.
+ $items[] = ['label' => esc_html__('Home', 'xshop'), 'url' => home_url('/'), 'current' => false];
+
+ if (is_front_page()) {
+ // Front page is current; keep only home as current.
+ $items[0]['current'] = true;
+ $items[0]['url'] = null;
+ } elseif (function_exists('is_woocommerce') && xshop_has_woocommerce() && (is_woocommerce() || is_cart() || is_checkout() || is_account_page())) {
+ // Delegate to Woo breadcrumb if available, but provide fallback.
+ if (function_exists('is_shop') && is_shop()) {
+ $items[] = ['label' => esc_html__('Shop', 'xshop'), 'url' => null, 'current' => true];
+ } elseif (function_exists('is_product_category') && is_product_category()) {
+ $shopUrl = function_exists('wc_get_page_permalink') ? wc_get_page_permalink('shop') : home_url('/');
+ $items[] = ['label' => esc_html__('Shop', 'xshop'), 'url' => $shopUrl, 'current' => false];
+ $term = get_queried_object();
+ if ($term instanceof WP_Term) {
+ $items[] = ['label' => $term->name, 'url' => null, 'current' => true];
+ }
+ } elseif (function_exists('is_product') && is_product()) {
+ $shopUrl = function_exists('wc_get_page_permalink') ? wc_get_page_permalink('shop') : home_url('/');
+ $items[] = ['label' => esc_html__('Shop', 'xshop'), 'url' => $shopUrl, 'current' => false];
+ $items[] = ['label' => get_the_title(), 'url' => null, 'current' => true];
+ } elseif (function_exists('is_cart') && is_cart()) {
+ $items[] = ['label' => esc_html__('Cart', 'xshop'), 'url' => null, 'current' => true];
+ } elseif (function_exists('is_checkout') && is_checkout()) {
+ $items[] = ['label' => esc_html__('Checkout', 'xshop'), 'url' => null, 'current' => true];
+ } elseif (function_exists('is_account_page') && is_account_page()) {
+ $items[] = ['label' => esc_html__('My Account', 'xshop'), 'url' => null, 'current' => true];
+ }
+ } elseif (is_home()) {
+ $postsPage = get_option('page_for_posts');
+ $label = $postsPage ? get_the_title((int) $postsPage) : esc_html__('Blog', 'xshop');
+ $items[] = ['label' => $label, 'url' => null, 'current' => true];
+ } elseif (is_category() || is_tag() || is_tax()) {
+ $term = get_queried_object();
+ if ($term instanceof WP_Term) {
+ $items[] = ['label' => $term->name, 'url' => null, 'current' => true];
+ }
+ } elseif (is_search()) {
+ $items[] = ['label' => sprintf(esc_html__('Search: %s', 'xshop'), get_search_query()), 'url' => null, 'current' => true];
+ } elseif (is_404()) {
+ $items[] = ['label' => esc_html__('Not Found', 'xshop'), 'url' => null, 'current' => true];
+ } elseif (is_singular()) {
+ $postType = get_post_type();
+ if ($postType && $postType !== 'post' && $postType !== 'page') {
+ $obj = get_post_type_object($postType);
+ if ($obj) {
+ $items[] = ['label' => $obj->labels->name, 'url' => null, 'current' => false];
+ }
+ } elseif ($postType === 'post') {
+ $cat = get_the_category();
+ if (!empty($cat[0])) {
+ $items[] = ['label' => $cat[0]->name, 'url' => get_category_link($cat[0]->term_id), 'current' => false];
+ }
+ }
+ $items[] = ['label' => get_the_title(), 'url' => null, 'current' => true];
+ } elseif (is_archive()) {
+ $items[] = ['label' => get_the_archive_title(), 'url' => null, 'current' => true];
+ }
+
+ // Mark last as current if none marked.
+ $hasCurrent = false;
+ foreach ($items as $it) { if (!empty($it['current'])) { $hasCurrent = true; break; } }
+ if (!$hasCurrent && count($items) > 0) {
+ $items[count($items) - 1]['current'] = true;
+ $items[count($items) - 1]['url'] = null;
+ }
+}
+
+// Never break if empty.
+if (empty($items)) { return; }
+
+// Allow SEO plugins / child themes to filter.
+$items = apply_filters('xshop_breadcrumbs_items', $items);
+if (empty($items) || !is_array($items)) { return; }
+?>
+
diff --git a/shop/xshop-theme/template-parts/components/empty-state.php b/shop/xshop-theme/template-parts/components/empty-state.php
new file mode 100644
index 0000000..4a0ad4a
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/empty-state.php
@@ -0,0 +1,23 @@
+
+
diff --git a/shop/xshop-theme/template-parts/components/hero.php b/shop/xshop-theme/template-parts/components/hero.php
new file mode 100644
index 0000000..3d93a7c
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/hero.php
@@ -0,0 +1,27 @@
+
+
diff --git a/shop/xshop-theme/template-parts/components/loading.php b/shop/xshop-theme/template-parts/components/loading.php
new file mode 100644
index 0000000..1da7a32
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/loading.php
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/shop/xshop-theme/template-parts/components/pagination.php b/shop/xshop-theme/template-parts/components/pagination.php
new file mode 100644
index 0000000..1e315fb
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/pagination.php
@@ -0,0 +1,41 @@
+max_num_pages <= 1) { return; }
+
+$big = 999999999;
+$links = paginate_links([
+ 'base' => str_replace((string) $big, '%#%', esc_url(get_pagenum_link((string) $big))),
+ 'format' => '?paged=%#%',
+ 'current' => max(1, (int) get_query_var('paged', 1)),
+ 'total' => (int) $query->max_num_pages,
+ 'prev_text' => is_rtl() ? esc_html__('Next', 'xshop') : esc_html__('Previous', 'xshop'),
+ 'next_text' => is_rtl() ? esc_html__('Previous', 'xshop') : esc_html__('Next', 'xshop'),
+ 'type' => 'array',
+ 'mid_size' => 1,
+ 'end_size' => 1,
+]);
+
+if (empty($links) || !is_array($links)) { return; }
+?>
+
diff --git a/shop/xshop-theme/template-parts/components/post-card.php b/shop/xshop-theme/template-parts/components/post-card.php
new file mode 100644
index 0000000..5a46325
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/post-card.php
@@ -0,0 +1,45 @@
+
+>
+
+
+ 'lazy', 'decoding' => 'async', 'alt' => esc_attr($title)]); ?>
+
+
+
+
+
+
diff --git a/shop/xshop-theme/template-parts/components/promo-banner.php b/shop/xshop-theme/template-parts/components/promo-banner.php
new file mode 100644
index 0000000..c1b9176
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/promo-banner.php
@@ -0,0 +1,26 @@
+
+
diff --git a/shop/xshop-theme/template-parts/components/search-form.php b/shop/xshop-theme/template-parts/components/search-form.php
new file mode 100644
index 0000000..91e8a77
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/search-form.php
@@ -0,0 +1,20 @@
+
+
diff --git a/shop/xshop-theme/template-parts/components/section-heading.php b/shop/xshop-theme/template-parts/components/section-heading.php
new file mode 100644
index 0000000..edd17a9
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/section-heading.php
@@ -0,0 +1,25 @@
+
+
diff --git a/shop/xshop-theme/template-parts/components/site-footer.php b/shop/xshop-theme/template-parts/components/site-footer.php
new file mode 100644
index 0000000..bdf21f1
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/site-footer.php
@@ -0,0 +1,53 @@
+
+
+
+
+
+
diff --git a/shop/xshop-theme/template-parts/components/site-header.php b/shop/xshop-theme/template-parts/components/site-header.php
new file mode 100644
index 0000000..8fe74e7
--- /dev/null
+++ b/shop/xshop-theme/template-parts/components/site-header.php
@@ -0,0 +1,80 @@
+
+
+
+
+ +
+ ++ 'ol', + 'short_ping' => true, + 'avatar_size' => 40, + 'max_depth' => (int) get_option('thread_comments_depth', 5), + ]); + ?> +
+ + is_rtl() ? esc_html__('Next', 'xshop') : esc_html__('Previous', 'xshop'), + 'next_text' => is_rtl() ? esc_html__('Previous', 'xshop') : esc_html__('Next', 'xshop'), + 'class' => 'xshop-pagination', + ]); + ?> + + + + + + + + + + + + + + + + '', + 'title_reply_after' => '
', + 'class_submit' => 'xshop-btn xshop-btn--primary', + 'submit_button' => '', + ]); + ?> +