diff --git a/shop/.editorconfig b/shop/.editorconfig deleted file mode 100644 index ec48fee..0000000 --- a/shop/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 8b231d6..0000000 --- a/shop/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 1abdbc2..0000000 --- a/shop/CHANGELOG.md +++ /dev/null @@ -1,48 +0,0 @@ -# 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. -- **M1.1 — Runtime QA**: - - Local XAMPP WP 7.1 + WC 11.1.0 + PHP 8.2.12 — 29 tests all PASS, 2 bugs fixed (`.htaccess` + ZIP wrapper), `docs/RUNTIME-QA.md` + `.gitignore` update, `tools/build-release.ps1` fix. -- **M2 — WooCommerce Storefront Foundation**: - - `assets/css/woo.css` (shop toolbar, product grid 4/3/2/1, card badges/price/rating, single gallery/thumbs/tabs/related, cart responsive table, mini-cart, account 220|1fr, checkout col2-set — logical props, token-based, dark-mode via semantic tokens). - - Components: `product-card.php` (WC_Product sale%/outofstock/featured/no-image/long titles, hook `xshop_product_card_after_actions`), `product-grid.php`, `product-gallery.php` (keyboard Arrow/Home/End, `is-active`), `mini-cart.php` (count/items/subtotal/remove/empty). - - Woo integration: `inc/woocommerce/setup.php` (loop_start/end `xshop-products`, toolbar, remove gallery, related 4/4, `product.js` conditional on `is_product()`), `inc/setup/assets.php` (woo.css global intentional, documented). - - Templates: `woocommerce/content-product.php:3.6.0`, `archive-product.php:3.4.0`, `content-single-product.php:3.6.0`, `single-product.php:1.6.4` (all minimal, versioned, hooks preserved). - - JS: `assets/js/product.js` (gallery thumbs, 40 lines, vanilla). - - Data: variable product 24 with 3 real variations (S 120k instock 10 / M 150→130k outofstock / L 180k) — attribute `Size` S/M/L, `data-product_variations` JSON, `reset_variations`. - - Runtime: shop/category/empty, simple/sale/no-image/outofstock/variable, gallery, cart quantity/coupon/totals/empty, account, checkout, RTL/LTR, dark, mobile — 18 tests PASS, 2 bugs fixed (coming-soon + `global $product: Type` parse error), `debug.log` clean, ZIP rebuild + manual install PASS. - - Docs: `ARCHITECTURE.md`, `UI-SPEC.md`, `TESTING.md`, `COMPATIBILITY.md`, `RUNTIME-QA.md` updated. -- **M3 — WooCommerce AJAX Product Search (REST-first)**: - - Endpoint `GET /wp-json/xshop/v1/search` (`xshop-core/includes/REST/Search.php:1`, `Core/Plugin.php`) — public `__return_true`, sanitized `search` (strip_tags/sanitize_text_field/max 100) + `limit` 1..20, min 2 → empty, `WP_Query s` + `_sku` LIKE, `publish` only, `no_found_rows` `fields ids` deduped to limit default 6, response `{items:[id,title,url,image,price_html,type,in_stock],total}` + `Cache-Control: public, max-age=60`, no private/draft/customer/order, SKU + title/content search, HPOS-safe. - - UI: `template-parts/components/ajax-search.php:1` reusable combobox (`role=combobox` `aria-expanded/controls/autocomplete` `listbox` `aria-live` `data-*`, view-all `?s=&post_type=product`, hidden `post_type` when Woo active, RTL via logical, dark via tokens). - - JS: `assets/js/search.js:1` vanilla debounce 250ms, `AbortController`, stale `seq`, dedupe `lastQuery`, `fetch`, loading/empty/error/view-all, keyboard `ArrowUp/Down/Enter/Escape`, `click outside`, `aria-activedescendant`, no `console.log`. - - Style: `assets/css/woo.css:1` dropdown `absolute→fixed@640` `max 60vh` `token` search item grid `48px 1fr` + price/stock. - - Asset: `inc/setup/assets.php:1` enqueue `search.js` only where `data-xshop-search` (header front-end, init guard), versioned. - - Security: strict sanitization/validation, bounded limit/length, no private data, escaped output, abuse note in `SECURITY.md` (rate limit via proxy). - - Performance: debounce, bounded, stale cancel, dedupe, `Cache-Control`, minimal payload, documented in `PERFORMANCE.md`. - - Runtime: endpoint Persian/English/SKU/no-result/1-char/empty/xss/limit, Woo on/off fallback to posts, desktop/mobile/RTL/dark, no stale overwrite, `debug.log` clean. - - Docs: `ARCHITECTURE.md:7` `UI-SPEC.md:3,8` `SECURITY.md:11` `PERFORMANCE.md:8` `TESTING.md:M3` `RUNTIME-QA.md:M3`. -- **M4 — WooCommerce AJAX Product Filtering (REST-first, shared ProductQuery)**: - - Query: `xshop-core/includes/Query/ProductQuery.php:1` — `sanitize_search_param` `map_orderby` `build_product_query_args` (search/category/pa_* attributes/price/stock/sale/rating/orderby/page/per_page → `tax_query` + `meta_query` + `orderby` + `Cache-Control`), `format_product` `execute_query`, no raw SQL, no N+1, HPOS-safe. - - Endpoint `GET /wp-json/xshop/v1/products` (`REST/Products.php:1`, `Core/Plugin.php`) — public, `search` max 100, `category` slug/ID, dynamic `pa_*` (only `taxonomy_exists`), `min/max_price` 0..99M + `min<=max` 400, `stock all/instock/outofstock`, `on_sale 0/1` via `_sale_price OR _min_variation_sale_price`, `rating 0..5`, `orderby` allow-list, `page 1..100` `per_page 1..24` default 12, response `{items:[id,title,url,image,price_html,type,in_stock], pagination:{page,per_page,total,total_pages}}` + `public, max-age=30`, M3 refactored to use `Query`. - - UI: `template-parts/components/product-filters.php:1` — `data-xshop-filters` + `chips` + `form method=get` no-JS fallback (category radio, `pa_*` checkbox, price number, stock radio, sale checkbox, rating radio, orderby select, `Apply/Clear all`, hidden `s`), `woocommerce/archive-product.php:1` — `xshop-shop` layout `sidebar 280px|1fr` + `drawer dialog` + `overlay` + `toolbar` + `grid` + `chips` + `loading/error`. - - JS: `assets/js/filter.js:1` (8KB) — `parseStateFromURL` `stateToParams` `stateToEndpoint` `renderProductCard` (reuses `product-card` structure), `renderChips` + `Clear all`, `URLSearchParams` + `history.pushState` + `popstate` back/forward, `debounce 300ms` for price, `AbortController` + `seq` stale guard, `click outside` `Escape` drawer `focus trap` + `aria-expanded/controls` `role=dialog` `aria-modal`. - - Style: `assets/css/woo.css:1` — `.xshop-shop__layout` responsive, `.xshop-chip`, `.xshop-filter` card, `.xshop-drawer` fixed, RTL via `inset-inline`, dark via tokens. - - Asset: `inc/setup/assets.php:1` — `filter.js` front-end with DOM guard (`data-xshop-filters`), versioned, `woo.css` global intentional. - - Server fallback: `inc/woocommerce/setup.php:1` `pre_get_posts` `xshop_wc_filter_main_query` — `ProductQuery::build_product_query_args` → `tax_query/meta_query` for no-JS `?stock=instock` etc. - - Security: strict sanitization/validation, bounded, `taxonomy_exists` allow-list, `post_status publish` only, `post__in` for sale via Woo lookup, no private data, `permission_callback __return_true` public read-only, documented. - - Performance: bounded `per_page 24`, `no_found_rows` `fields ids` for search, `Cache-Control`, debounce, stale cancel, dedupe, minimal payload. - - Runtime: direct REST `category/price/stock/sale/rating/price_asc/pagination/search+filter` all PASS, server `?stock=instock` PASS, browser E2E (Playwright) category/sale/price/stock/sort/pagination/rapid/back/forward/drawer/search+filter all PASS (minor duplicate form fix), `debug.log` clean. - diff --git a/shop/README.md b/shop/README.md deleted file mode 100644 index e587fa2..0000000 --- a/shop/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# 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 deleted file mode 100644 index 710b0c7..0000000 --- a/shop/docs/ADR/001-no-custom-tables-v1.md +++ /dev/null @@ -1,17 +0,0 @@ -# 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 deleted file mode 100644 index a10cdda..0000000 --- a/shop/docs/ADR/002-rest-over-admin-ajax.md +++ /dev/null @@ -1,17 +0,0 @@ -# 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 deleted file mode 100644 index dd6b27e..0000000 --- a/shop/docs/ARCHITECTURE.md +++ /dev/null @@ -1,156 +0,0 @@ -# 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 (M4) - -``` -xshop-theme/ - inc/setup/assets.php — tokens→…→woo→utilities + theme.js + search.js + filter.js (front-end, DOM guard, documented) - inc/woocommerce/setup.php — loop, toolbar, gallery, related, product.js, pre_get_posts no-JS fallback - assets/css/woo.css — + search + filters (.xshop-shop, _filters, _chip, _drawer, responsive) - assets/js/search.js — debounce 250ms, AbortController, stale seq - assets/js/filter.js — URL sync, chips, debounce 300ms for price, AbortController, drawer a11y - template-parts/components/ajax-search.php + product-filters.php (sidebar+drawer, no-JS fallback) - woocommerce/archive-product.php — shop/category with filters layout + chips + AJAX grid -xshop-core/ - includes/Query/ProductQuery.php — shared sanitize, map_orderby, build_product_query_args, format_product, execute_query - includes/REST/Search.php — refactored to use Query - includes/REST/Products.php — xshop/v1/products (category, pa_*, price, stock, sale, rating, orderby, pagination, search) - includes/Core/Plugin.php — loads Query + both REST -``` - -### 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 (M2) - -Tokens: `tokens.css` unchanged — adds WC tokens `--xshop-wc-badge-sale/--xshop-wc-price` etc. Layering `tokens→base→layout→components→woo→utilities→style.css` (woo.css 159 lines, tokens for shop/product/cart). Dark mode semantic swap covers `bg/surface/card/text/muted/border/input/focus/link/notice` — verified on shop/card/gallery/tabs/cart/checkout. Logical props only, zero `left/right`. - -## 6. Asset Strategy (M2) - -- Vanilla JS: `theme.js` (deferred) + `product.js` (enqueued only on `is_product()` via `xshop_wc_single_setup` guard). No gallery framework, 40 lines, keyboard Arrow/Home/End. -- Enqueue: `tokens→base→layout→components→woo→utilities→style.css` chain in `inc/setup/assets.php:1` (`woo.css` **intentionally global** 12KB — replaces Woo's 3 stylesheets, avoids FOUC on shop/product/cart/account; documented, tiny vs conditional complexity). WC styles dequeued (`woocommerce_enqueue_styles → __return_empty_array`). `product.js` conditional, `comment-reply` conditional. -- Localized `xshopData` on `xshop` handle. No jQuery for theme code; Woo's jQuery remains for variations/add-to-cart. -- Build: `tools/build-release.ps1` now includes top-level folder `xshop/` wrapper (fixed in M1.1). - -## 7. AJAX / REST (M4) - -- **Search** (M3): `GET /wp-json/xshop/v1/search?search=&limit=` — public, `search` max 100 + `limit` 1..20, min 2, `WP_Query s` + `_sku LIKE`, `publish` only, `no_found_rows` `fields ids`, `{items:[id,title,url,image,price_html,type,in_stock],total}` + `Cache-Control: public, max-age=60`, shared `Query\ProductQuery`. -- **Products** (M4): `GET /wp-json/xshop/v1/products?search=&category=&pa_*=&min_price=&max_price=&stock=&on_sale=&rating=&orderby=&page=&per_page=` — public, sanitized `search` + `category` slug/ID + dynamic `pa_*` (only `taxonomy_exists`), `min/max` numeric 0..99M + `min<=max` 400, `stock all/instock/outofstock`, `on_sale 0/1` via meta OR, `rating 0..5` via `_wc_average_rating`, `orderby` allow-list `default/latest/price_asc/desc/popularity/rating/date` → `map_orderby`, `page 1..100` `per_page 1..24` default 12, shared `ProductQuery::build_product_query_args` → `WP_Query` `tax_query` + `meta_query` + `orderby` + `post__in` for sale, `execute_query` → `{items, pagination:{page,per_page,total,total_pages}}` + `Cache-Control: public, max-age=30`, no private data, no N+1. -- Prefer REST for search/filter, fallback `admin-ajax` for cart. - -## 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 (M2) - -`header.php` → `site-header` + breadcrumbs; `footer.php` → `site-footer`. Content templates use Loop + `get_template_part`. Reusable: `product-card.php:1` (WC_Product badges/price/rating, hook `xshop_product_card_after_actions`), `product-grid.php:1`, `product-gallery.php:1` (featured+thumbs, keyboard). `front-page.php` section-based via `xshop_front_hero_args`. - -**Woo overrides (4, all minimal, versioned):** -- `woocommerce/content-product.php` (3.6.0) — Why: grid/token alignment; Hooks/CSS insufficient (li.product markup). Minimal: single `
  • ` + `get_template_part product-card`. Risk: Woo 3.6 → bump → re-check `wc_product_class`. -- `woocommerce/archive-product.php` (3.4.0) — Why: XShop header (category title/desc/count) + toolbar + empty-state CTA. Hooks could do header but empty-state needs override. Minimal. -- `woocommerce/content-single-product.php` (3.6.0) — Why: grid layout `.xshop-product` gallery+summary + custom gallery component. Hooks alone can't provide grid wrapper without CSS hacks. Minimal: wraps hooks, replaces `woocommerce_show_product_images`. -- `woocommerce/single-product.php` (1.6.4) — Delegator to `content-single-product.php`; kept for explicitness, could be removed (Woo default works) but retained for clarity. - -All keep Woo hooks (`woocommerce_before_single_product`, `woocommerce_single_product_summary`, `woocommerce_after_single_product_summary` etc.) — no business logic rewrite. `inc/woocommerce/setup.php:1` handles `loop_start/end` filter (`xshop-products`), toolbar `woocommerce_before_shop_loop` 9/35, remove gallery, related args `posts_per_page 4 columns 4`. - -## 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 deleted file mode 100644 index 2937ba5..0000000 --- a/shop/docs/COMPATIBILITY.md +++ /dev/null @@ -1,46 +0,0 @@ -# XShop – Compatibility - -## 1. Tested Up To (M4: 2026-09-13) - -| Dependency | Minimum | Tested | -|------------|---------|--------| -| WordPress | 6.4 | 7.1 | -| WooCommerce| 8.0 | 11.1.0 | -| PHP | 8.2 | 8.2.12, 8.3 recommended | -| Elementor | 3.15 (optional) | 3.2x | -| Gutenberg | WP bundled | — | -| Browsers | last 2 versions | 360/390/768/1024/1280/1440 via Playwright + CSS | - -## 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 (M4) - -- `add_theme_support('woocommerce')` + wrappers, loop `xshop-products`, toolbar, `product.js` conditional, `search.js`+`filter.js` front-end (DOM guard). -- REST: `xshop/v1/search` + `xshop/v1/products` (shared `ProductQuery`), HPOS via `wc_get_products`/`WP_Query`, no raw SQL. -- Overrides (4): `content-product.php 3.6.0`, `archive-product.php 3.4.0` (now with `xshop-shop` layout + `product-filters` sidebar/drawer + `pre_get_posts` no-JS fallback), `content-single-product.php 3.6.0`, `single-product.php 1.6.4`. - -## 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 deleted file mode 100644 index e439dd2..0000000 --- a/shop/docs/DATABASE-MODEL.md +++ /dev/null @@ -1,80 +0,0 @@ -# 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 deleted file mode 100644 index 6838b25..0000000 --- a/shop/docs/FEATURE-MATRIX.md +++ /dev/null @@ -1,95 +0,0 @@ -# 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 deleted file mode 100644 index cbbfcf7..0000000 --- a/shop/docs/PERFORMANCE.md +++ /dev/null @@ -1,61 +0,0 @@ -# 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. Search Performance (M3) - -- **Debounce**: 250ms in `assets/js/search.js:debounce` (200–300ms target). Prevents request on every keystroke. -- **Min length**: 2 chars (handler returns empty without query). Input `data-min-length`. -- **Bounded**: `limit` default 6, max 20, validated; handler over-fetches `limit*2` for dedup then slices to `limit`; max 40 IDs scanned. -- **Stale protection**: `AbortController` cancels previous fetch + monotonic `seq` counter ignores stale JSON; rapid `iph → iphone` cannot overwrite newer. -- **Dedupe**: identical query (`lastQuery`) reopens dropdown without fetch. -- **Query**: `WP_Query` `s` + `_sku` LIKE, `post_status publish`, `no_found_rows`, `fields ids`, no N+1, `wc_get_product` only for returned IDs (≤6). -- **Asset**: `search.js` enqueued only on front-end where `data-xshop-search` exists (header on all front-end pages, guarded via `initAll`); `woo.css` global intentional. -- **Caching**: server `Cache-Control: public, max-age=60`; no client cache beyond in-memory `lastQuery` (no stale invalidation issues). -- **Payload**: minimal 6 items × 6 fields (~2KB JSON). - -## 9. 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 deleted file mode 100644 index a6e9c81..0000000 --- a/shop/docs/PRODUCT-SPEC.md +++ /dev/null @@ -1,90 +0,0 @@ -# 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 deleted file mode 100644 index c52801f..0000000 --- a/shop/docs/ROADMAP.md +++ /dev/null @@ -1,60 +0,0 @@ -# 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 deleted file mode 100644 index 75cf45a..0000000 --- a/shop/docs/RUNTIME-QA.md +++ /dev/null @@ -1,209 +0,0 @@ -# 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). - ---- - -# M2 — WooCommerce Storefront Foundation (2026-09-13) - -## Environment (same as M1.1, plus M2 data) - -Same XAMPP WP 7.1 / WC 11.1.0 / PHP 8.2.12, with additional products: -- 22 `لپ‌تاپ فوق‌العاده ایسوس...` sale 40M→32M (-20%) -- 23 `Out of Stock Test...` very long English title, `in_stock=false` -- 24 `تیشرت متغیر — تست سایز و رنگ` variable, attribute `Size` S/M/L, variations: 26 S 120k instock 10, 27 M 150k→130k outofstock, 28 L 180k instock (created via `WC_Product_Variation` PHP, synced via `WC_Product_Variable::sync(24)`). Fixed case mismatch (lowercase s/m/l vs S/M/L — now uppercase S/M/L). -- 19 `دسته خالی تست` empty category - -`woocommerce_coming_soon` + `woocommerce_store_pages_only` were `yes` → shop showed `Great things are on the horizon` coming-soon block; fixed via `option update ... no` (M2 bug #1). `product-card.php` Parse error `global $product: WC_Product` → fixed to `global $product` (M2 bug #2). - -## Test Cases (M2 — 18 additional, all PASS) - -| # | Test | Method | Result | -|---|------|--------|--------| -| 30 | Shop grid — 4 products, toolbar, sorting, result count "Showing all 4 results" | `GET /shop/` | **PASS** `xshop-products` `xshop-product-card` `woocommerce-ordering` `result-count` `xshop-shop-toolbar` | -| 31 | Shop — sale badge -20% (product 22) + outofstock + featured logic | `GET /shop/` inspect cards | **PASS** `-20%` `Out of stock` badges via tokens | -| 32 | Category empty — `دسته خالی تست` | `GET /product-category/دسته-خالی-تست/` | **PASS** `No products found` + CTA `Browse shop` | -| 33 | Simple sale product 22 — gallery, price del/ins, stock, add-to-cart | `GET /?post_type=product&p=22` | **PASS** `xshop-product__gallery` `xshop-product__price` `add_to_cart` | -| 34 | Simple no-image 21 — placeholder, no-image gallery fallback | `GET /?p=21` | **PASS** `No image` placeholder, gallery single main | -| 35 | Variable 24 — attribute select S/M/L, `data-product_variations` JSON with 3 variations, prices 120k/130k/180k, availability 10 in stock / Out of stock, `reset_variations` link, select renders S/M/L | `GET /?p=24` | **PASS** `variations_form` `data-product_variations` `select` options S/M/L | -| 36 | Variable — select S → price 120k in-stock, select M → price 130k (sale 150→130) out-of-stock, select L → 180k | Inspect JSON + manual select (JS) | **PASS** `display_price` 120000/130000/180000, `availability_html` 10 in stock / Out of stock | -| 37 | Variable — add S (120k) to cart, add L (180k) qty 2 | `GET /?add-to-cart=24&variation_id=26&attribute_size=S` + `...28...L` | **PASS** cart contains S `120,000` and L `180,000` qty 2; M out-of-stock `is_in_stock:false` correctly blocked in UI (direct GET bypassed but UI `is_in_stock` is false) | -| 38 | Cart — table, quantity input `name="cart["`, coupon, `cart_totals`, remove link, totals | `GET /cart/` via session | **PASS** `shop_table` responsive `data-title`, `coupon`, cart item `Restore Product` | -| 39 | Cart — quantity update, remove | Add 21 then `cart` | **PASS** quantity input present | -| 40 | Mini-cart component | `template-parts/components/mini-cart.php` + `GET /cart/` session | **PASS** `xshop-mini-cart` count/items/subtotal, empty state rendered via component | -| 41 | Account — dashboard/orders/addresses/details/login/lost-password, mobile RTL | `GET /my-account/` | **PASS** `MyAccount-navigation` 220px|1fr → stacked @900, `lost_password` found | -| 42 | Checkout — billing/shipping/review/payment, mobile | `GET /checkout/` | **PASS** `woocommerce-billing-fields` `payment_method` `order_review` | -| 43 | Gallery — featured+thumbs keyboard Arrow/Home/End, `is-active`, RTL, no-gallery fallback | `GET /?p=22` + JS | **PASS** `xshop-product__thumbs` `role=tablist` `is-active`, `product.js` vanilla | -| 44 | Dark mode — shop/card/gallery/tabs/cart/checkout/account via tokens | CSS + HTML `data-theme` | **PASS** `var(--xshop-card)` etc, no second dark system | -| 45 | Mobile — viewports 360/390/768/1024/1280/1440 (CSS grid 4→3→2→1, shop_table block, col2-set 1fr, nav stacked) | CSS + manual fetch | **PASS** no `left/right`, logical props, no horizontal overflow | -| 46 | RTL — Persian `dir=rtl`, shop/product/cart/account/checkout/gallery/forms/notices/pagination | `site switch-language fa_IR` → `GET /shop/` | **PASS** `dir=rtl` `xshop--rtl` | -| 47 | PHP QA — `php -l` all, `node --check`, no TODO/console.log/var_dump, `debug.log` clean after 10 hits | CLI | **PASS** | - -**Total M2: 18 tests — 18 PASS.** - -## Known Issues (M2) - -- Woo `_load_textdomain_just_in_time` notice (upstream, not XShop) — filtered. -- `wp theme install ` still warns on empty `languages/` dir — manual `Expand-Archive` (WP admin) is canonical; documented in M1.1. -- `woocommerce_store_pages_only`/`coming_soon` default `yes` in WC 11.1 — must be disabled via `option update ... no` for local dev; documented. - -## Conclusion - -**M2 ACCEPTED** — Shop/category/grid/card/sorting/pagination/empty, product gallery + variable with real variations (price/stock reset/add-to-cart), cart quantity/coupon/totals/empty, mini-cart, account, checkout, RTL/LTR/dark/mobile, no XShop PHP/JS errors, ZIP installs via Expand-Archive. - ---- - -# M3 — AJAX Search (2026-09-13) - -## Endpoint - -- `GET /wp-json/xshop/v1/search?search=Test&limit=6` → `200 {"items":[{"id":23,"title":"Out of Stock Test...","url":"...","image":"...","price_html":"...","type":"simple","in_stock":false}],"total":1}` — verified via `Invoke-WebRequest`. -- **Persian**: `search=لپ` → product 22 sale `-20%`; `search=Restore` → 21; `SKU XSHOP-SKU-123` → 21. -- **Validation**: `search` >100 → 400, `limit` >20 → 400, `search` 1-char / empty / whitespace → `{"items":[],"total":0}` 200, `limit` default 6 enforced. -- **Security**: `sanitize_text_field` + `wp_strip_all_tags` + `mb_substr 100`, `absint` 1..20; only `publish` products; no `post_password`/customer/order; `price_html` from Woo trusted; no `TODO`/`console.log`. -- **Woo inactive**: deactivated Woo → `search=Hello` → 2 posts `type post` with `price_html ""` (fallback), re-activated Woo → product search restored. - -## UI - -- Header `data-xshop-search` markup present on `GET /` → `xshop-search__dropdown` + `search.js` enqueued (`