157 lines
8.6 KiB
Markdown
157 lines
8.6 KiB
Markdown
# 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 `<li>` + `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.
|