=== TitanCart Lite ===
Contributors: titancart
Tags: ecommerce, shop, store, cart, products
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 0.2.30
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

A self-hosted eCommerce engine for WordPress. Own tables, own REST API, own admin. No extra plugins. No page-builder bloat.

== Description ==

TitanCart is a complete storefront in one plugin: catalog, cart, checkout, orders, customers, shipping, tax and reporting. It runs on its own database tables and its own REST API rather than bending WordPress posts and meta into a shopping cart, which is why it stays fast as a catalog grows.

No license key is required. TitanCart Lite is free and GPL, and it never contacts a remote server.

= What you get =

* **Products** — simple and variable products, categories, product filters, attributes, image galleries, digital downloads.
* **Cart and checkout** — a real cart session, guest checkout, coupon codes, order notes.
* **Payments** — Stripe, plus cash on delivery, bank transfer and cheque.
* **Shipping** — flat rate, free shipping, and table-based rates with zones and conditions.
* **Tax** — full tax classes, zones and rate rules. Not a stripped-down version; tax is a legal requirement, not an upsell.
* **Orders** — order management, statuses, invoices, fulfilment and shipment tracking.
* **Customers** — accounts, address book, order history, customer groups.
* **Reviews** — product reviews with moderation.
* **Wishlists**, **sitemap**, **SEO** output (meta tags, canonical URLs, Open Graph, JSON-LD product schema), **GDPR** tools and **age verification**.
* **Import and export** — CSV import and export, including a WooCommerce migration tool.
* **Prism** — a free companion storefront theme built for TitanCart, available as a free download from the TitanCart marketplace at market.titancart.io.

= Built to be portable =

TitanCart's cart, checkout, order and pricing logic have no WordPress function calls inside them. WordPress is a thin hosting layer over a self-contained engine. That is an architectural choice, not marketing: it is what keeps the query count low and the upgrade path open.

= Privacy and external services =

TitanCart Lite makes **no outbound connections of any kind** on its own. It contains no license check, no update checker, no analytics, no telemetry, and no remote code installer. Updates arrive through WordPress.org like any other plugin.

A small number of features contact a third party only after **you** configure them, using credentials you supply. Each is documented in the External services section below. None is enabled by default.

= Source code =

The admin interface, `admin/build/titancart-admin.js`, is hand-written JavaScript and **is itself the source code**: there is no build step, no transpiler, no JSX, no bundler and no minification anywhere in this plugin. The directory name is historical. The same is true of every other JavaScript and CSS file shipped — what you read in the ZIP is exactly what the developer wrote and maintains.

== Installation ==

1. In your WordPress admin, go to Plugins → Add New and search for "TitanCart".
2. Click **Install Now**, then **Activate**.
3. Follow the setup prompt, or go to **TitanCart → Settings** to configure your store, currency, shipping and tax.
4. Optionally install the free **Prism** storefront theme, available from the TitanCart marketplace at market.titancart.io.

No account, key or sign-up is required.

== External services ==

TitanCart Lite connects to the following external services. Every connection is **off by default** and happens only after the site owner configures the feature with their own credentials or explicitly triggers it with a click.

**Stripe (payment processing)**

* What it is: card payment processing by Stripe, Inc.
* What it is used for: charging customers at checkout when the store owner has created a Stripe payment method with their own API keys.
* What data is sent, and when: when a Stripe method is enabled, the checkout page loads Stripe's `Stripe.js` from `js.stripe.com` (a Stripe requirement for PCI compliance) and card details entered by the customer go **directly from the customer's browser to Stripe** — they never touch the store's server. The server then exchanges payment intents/confirmations with Stripe's API (order amount, currency, and the payment reference).
* Terms and privacy: [Stripe Services Agreement](https://stripe.com/legal/ssa), [Stripe Privacy Policy](https://stripe.com/privacy).

**Google reCAPTCHA (spam and abuse protection)**

* What it is: Google's reCAPTCHA v2/v3 service.
* What it is used for: protecting the login, registration, checkout, review and contact surfaces from bots — only if the store owner enables the reCAPTCHA feature and supplies their own site key and secret.
* What data is sent, and when: on pages with a protected form, Google's `api.js` loads from `www.google.com` in the visitor's browser (Google's script collects the signals it uses for its bot score — see its privacy policy); on submit, the server sends the response token, the site secret and the visitor's IP address to Google's `siteverify` endpoint to obtain the verdict.
* Terms and privacy: [Google Terms of Service](https://policies.google.com/terms), [Google Privacy Policy](https://policies.google.com/privacy).

**Google Maps Places (address autocomplete)**

* What it is: the Google Maps JavaScript API with the Places library.
* What it is used for: suggesting street addresses as a customer types on the checkout and account address forms — only if the store owner turns on **Address autocomplete** in checkout settings and supplies their own Google Maps API key. Off by default; nothing loads without the key.
* What data is sent, and when: on the checkout and account pages only, the visitor's browser loads `maps.googleapis.com/maps/api/js` (keyed with the owner's API key) and sends the characters typed into the address field to Google to receive suggestions. The store's server never contacts Google for this feature.
* Terms and privacy: [Google Maps Platform Terms](https://cloud.google.com/maps-platform/terms), [Google Privacy Policy](https://policies.google.com/privacy).

**YouTube and Vimeo (product video embeds)**

* What it is: the public video players of YouTube (Google) and Vimeo.
* What it is used for: showing a product video on the product page when the store owner has pasted a YouTube or Vimeo link into that product's video field. No video is embedded unless the owner adds one.
* What data is sent, and when: the product page renders a thumbnail from `img.youtube.com` and, when the visitor clicks play, an embedded player from `www.youtube.com` or `player.vimeo.com` in the visitor's browser; those providers receive the visitor's request as with any embedded video. In the admin product editor, a thumbnail preview is fetched from `img.youtube.com` for the link the owner entered. Videos hosted on the store's own server are played directly and involve no third party.
* Terms and privacy: [YouTube Terms of Service](https://www.youtube.com/t/terms), [Google Privacy Policy](https://policies.google.com/privacy), [Vimeo Terms of Service](https://vimeo.com/terms), [Vimeo Privacy Policy](https://vimeo.com/privacy).

**Remote images during CSV import**

* What it is: standard HTTP downloads performed by WordPress itself.
* What it is used for: when the store owner runs a product CSV import whose rows contain image URLs, WordPress downloads those images into the media library.
* What data is sent, and when: an HTTP GET to each image URL **the owner provided in their own file**, at import time only.

**Demo content for the Prism theme (market.titancart.io)**

* What it is: ready-made demo packages (products, categories, attributes and banner images) published by TitanCart for its free Prism storefront theme, which is a separate download.
* What it is used for: letting a store owner who has installed Prism fill an empty store with matching sample content from **Theme Options → Demo content → Install demo**, and later reinstall, clear or remove it.
* What data is sent, and when: only when the owner clicks Install, Switch or Reinstall does the server fetch the list of available demos and then the chosen package (a JSON file plus its images) from `market.titancart.io` over HTTPS — ordinary GET requests carrying no store data. Opening the Theme Options page does not contact the service. Nothing is fetched on sites without Prism.
* Terms and privacy: [TitanCart Privacy Policy](https://titancart.io/privacy/).

The product page's optional share buttons are ordinary links to Facebook, X, Pinterest and LinkedIn share pages; nothing is loaded from those sites and no request is made unless the visitor clicks one.

No other external connections exist in TitanCart Lite. Payment gateways beyond Stripe (PayPal, Square, Authorize.net), live carrier shipping rates (USPS, FedEx), social sign-in (Google, Facebook, Apple) and the TitanCart extensions catalog are features of TitanCart Pro, are **not present in this plugin's code**, and are documented in the Pro edition's own materials.

== Frequently Asked Questions ==

= Do I need a license key? =

No. TitanCart Lite is free, GPL-licensed, and fully functional without a key. It never asks for one and never phones home.

= Will it work alongside WooCommerce? =

TitanCart does not use, extend or depend on WooCommerce, and it stores nothing in WooCommerce's tables. Running both at once is not recommended simply because two storefronts on one site confuses customers, not because they conflict technically. There is a built-in WooCommerce importer to migrate your catalog across.

= Does it slow my site down? =

TitanCart uses its own indexed tables instead of `wp_postmeta`, so catalog queries do not scale with your meta table. The admin is a single-page app that loads once and then talks to a REST API.

= What is the difference between Lite and Pro? =

Lite is a complete, working store: products, cart, checkout, Stripe, shipping, tax, orders, customers, reviews, import/export and SEO. Pro adds promotions and discount rules, loyalty rewards, gift cards, product bundles and options, email campaigns, returns (RMA), advanced reporting, additional payment gateways, live carrier shipping rates, the external REST API, and the first-party extension suite.

Everything in Lite stays in Lite. Pro is additional capability, never a paywall in front of something that used to be free.

= Where is my data stored? =

In your own database, in tables prefixed `wp_tc_`. Nothing is stored off-site. Uninstalling is a clean removal.

== Screenshots ==

1. The storefront, running the free Prism theme (available from the TitanCart marketplace).
2. Product catalog in the TitanCart admin.
3. The product editor.
4. Order management and fulfilment.
5. Checkout.
6. Store settings.

== Changelog ==

= 0.2.27 =
* Theme Options: new "image set" control lets a theme take a separate photo and crop anchor for desktop, tablet and phone on one setting (used by TitanCart Prism 0.2.7 for the homepage hero). A photo already saved on a plain image setting keeps working as the desktop photo.

= 0.2.26 =
* Fixed: after upgrading to 0.2.25, every admin and storefront request could take a couple of seconds longer. The 0.2.25 upgrade step that creates the FAQ page ran before WordPress was ready, failed quietly, and left the upgrade unfinished, so its table check re-ran on every request. The step now waits for WordPress, finishes even if page creation is skipped, and runs once.
* Attributes: the Choices tab no longer shows a stray "0" column beside Hex Color on attributes without site-wide prices.

= 0.2.25 =
* New: FAQ page. Storefront → FAQ in the admin lets you add as many questions and answers as you need, group them by category and order them; put the [titancart_faq] shortcode on any page for an accordion (one answer open at a time, keyboard and screen-reader friendly) with FAQ structured data for search engines. Works with any theme. An "FAQ" page carrying the shortcode is created for you (or adopted if one exists).
* Fixed: TitanCart Lite no longer creates a "Gift Cards" page — gift cards are a Pro feature, so the page only showed the raw shortcode. The empty auto-created page is removed on upgrade (a page you have edited is kept).
* Attributes: a shared-variation attribute can now carry site-wide price changes. Turn on "Site-wide price changes" on the attribute, enter the amount per choice on its Choices tab (e.g. Large +5.00), and every product using it charges that — a product can still override any choice on its own Attributes tab, including 0 for "no change on this one".
* Product page: a shared-variation attribute shown as a dropdown no longer repeats the chosen value beside the attribute name (the dropdown already shows it).

= 0.2.24 =
* Fixed: a shared-variation attribute set to display type "Dropdown" now renders as a dropdown on the product page (it always showed pills). The dropdown shows any per-choice price change, updates the price as you pick, and the choice is carried into the cart like the pill and swatch styles.
* Product page: the Add to Cart button no longer gets squeezed when the browser window narrows. It keeps its full size; Wishlist and Compare shrink to icon buttons when the row runs short of room, and become full-width labelled buttons again on phones.
* Product page: switching a separate-product variation no longer leaves the previous size as a blank white pill while the next page loads (its text was fading out mid-frame).
* Attributes: choices can now be reordered with up/down arrows on the Choices tab (Manual order mode); the new order applies everywhere the choices appear — product pages, filters, the product editor.

= 0.2.23 =
* Variations (shared product — one product, choose Size/Colour on its page): each ticked choice on the product's Attributes tab can now carry a price change (e.g. Large +5.00, Small -2.00). The product page shows the amount on the choice and updates the price as the customer picks; the cart, checkout and order use the same figure and show it beside the choice ("Size: Large (+$5.00)").
* Variations (separate products): "Add Variations" can copy this product's description, short description and image gallery onto every new variation — two ticks in the dialog, on by default — so a family of sizes no longer needs the same photos and copy added by hand.
* Fixed: deleting an attribute (or a choice) that a variation group was built on no longer leaves the group pointing at nothing ("Attr #2 / Variant #6" on the Product Group tab). The group drops that axis, members whose choice is gone leave the group, and a group with no axis left is dissolved — the products themselves are untouched. Existing stores are cleaned up once on upgrade.
* Also carries every 0.2.22 fix below for stores whose 0.2.22 package was built before they landed (price-change fix, quantity limits on the product page, trimmed-quantity messages, quick-view quantity, cart spinner snap-back).

= 0.2.22 =
* Fixed: changing a product's price no longer leaves the storefront showing the old price. Products created before this release carried a hidden duplicate of their original price as a quantity-1 "bulk" tier; the editor re-saved it unchanged and the store kept charging it. The duplicate rows are removed on upgrade and are no longer created.
* Fixed: the product page's quantity control now stops at what the cart will accept (the units in stock when inventory is tracked without backorders, or the maximum per order) and shows "Only N available" when the stock is the limit. When the cart still has to trim a quantity, the message says so ("Only 1 available — 1 added to your cart") instead of a plain "Product added".
* Fixed: the quick-view popup's quantity box is now honoured by Add to Cart (it always added 1).
* Fixed: the cart page's quantity spinner snaps back to the accepted quantity when the store trims it.
* Variations: when creating variations you can now enter a price per attribute choice — either an amount added to the product's price (e.g. Large +5.00) or the variation's full price — and the preview shows the resulting price of every combination.
* Variations: the Product Group tab's price, quantity and product-code cells are now edited in place; they save when you leave the field.

= 0.2.21 =
* Storefront: changing a quantity on the cart page and saving order notes now work on hosts and sandboxes that strip the body of PUT/PATCH requests (including WordPress Playground). The cart script sends these as POST with a method-override header, exactly as the admin app has since 0.2.19. No change on normal hosts.

= 0.2.20 =
* Admin: if a store is set to the TitanCart Prism theme but Prism is not installed, a notice explains that Prism is a separate free download and links to it.
* Updates: Dashboard > Updates > "Check again" now re-asks the marketplace for extension updates instead of answering from a cached result.

= 0.2.19 =
* Admin: saving any settings page now works on hosts and sandboxes that strip the body of PUT requests (including WordPress Playground). The admin app sends its saves as POST with a method-override header, which WordPress's REST server maps back to the intended method before routing. No change on normal hosts.
* Demo content: installing a demo now records the storefront preset switch in System Logs like a manual switch does, and cleans up its "category scope" toggle when the demo is removed or switched.
* Theme Options: the active theme can now add controls to the "Active Theme" panel (the free Prism theme uses this for its update-channel license key); a `titancart_settings_saved` action fires after every settings save so the theme can react.

= 0.2.18 =
* Theme Options: the "Active preset" default now comes from the active theme instead of being hard-coded, so a fresh Prism install starts on a finished preset (Apparel) rather than the unfinished Indigo design. Requires Prism 0.2.1.

= 0.2.17 =
* Demo content for the Prism theme. With Prism installed, each preset panel in Theme Options now has a Demo content card: one click installs that preset's products, categories, attributes and banner images, then generates sample customers, orders and reviews (dated over the last 30 days) so the dashboard and reports have something to show. Sample data can be cleared on its own; the whole demo can be removed. Demos can be switched freely while the store is untouched; the first real product, category or order locks switching so your work is never overwritten. Images are fetched in small batches so the progress bar keeps moving on slow hosts. Requires the free Prism theme; packages are downloaded from market.titancart.io only when you click (see External services).
* New table `tc_demo_import_log` records everything a demo installed so reinstalls repair in place and removals are exact.
* Fixed: two admin notices used the wrong text domain.

= 0.2.16 =
* Admin: fixed an intermittent "Page Error" (insertBefore NotFoundError) in the Payment Gateways editor and other admin screens. Root cause: WordPress's emoji replacement script rewrites emoji characters inside the admin app's text into images behind React's back. The emoji script is no longer loaded on TitanCart admin screens (the same approach WordPress core uses for the block editor). Front-end and other admin pages are unaffected.
* Invoice and packing-slip print documents now load their styles as static stylesheets through the core styles API (wp_register_style / wp_add_inline_style / wp_print_styles) instead of embedded style blocks.
* Every intentionally public REST route now declares the literal __return_true permission callback with an inline justification comment at the registration site (anonymous storefront reads, guest cart/checkout session operations, token-as-credential links, moderated guest write-ins, signature-verified gateway webhooks/returns).
* Import: the CSV column help text for images no longer uses URL-shaped example strings.
* Fresh installs: activation now stamps the schema/migration state directly instead of replaying 63 historical migrations on first load. Fixes noisy database errors, a page-creation error before WordPress's rewrite system is ready, and a translations-loaded-too-early notice on brand-new installs (found testing on WordPress Playground). Existing sites are unaffected — migrations remain the upgrade path.
* Fresh installs: default fulfillment/gift-card statuses, reward-point earning rules, and return reasons are now seeded at activation; a stale email-template seeder that silently failed on every fresh install was removed (templates seed on first access, as designed).
* The reviewer/architecture notes document now ships in the package at docs/WPORG-REVIEWER-NOTES.md.
* WooCommerce import: variable products now import their variation values from each variation's own attribute data, so stores whose global attribute terms are missing or incomplete (some CSV-imported catalogs) no longer produce unlinked variations with an empty option selector. Attribute names fall back to a readable label ("Color") instead of the raw taxonomy slug, re-running the import repairs previously broken imports in place, and imported variable products now display as a single product card on the storefront by default (each variation keeps its own product code, price and stock). The single card is titled with the original product's name ("Hoodie") rather than a variation's name ("Hoodie — Blue / Yes"); re-running the import fills this in for groups created by an earlier version, without overwriting a name you have set yourself.
* Attribute choices and assigned attribute values now list correctly on SQLite-backed sites (WordPress Playground, WP-CLI/Plugin Check SQLite environments): the shared ordering clause used MySQL-only syntax (IF(), a MySQL collation name) that SQLite rejects, which emptied choice lists across the product editor, storefront filters and product-page selectors on those environments. The clause now uses standard SQL.

= 0.2.15 =
* Attributes: each attribute now has a "Sort Choices" setting — Manual order (default, unchanged for existing stores) or Alphabetical A–Z. The chosen order applies everywhere choices are listed: product editor, variation generator, storefront filters, product-page selectors and product-card swatches. Alphabetical sorting is collation-aware and case-insensitive, and never rewrites your manual order, so switching back restores it.
* Attributes: one-click "Sort A–Z now" on the Choices tab rewrites the manual order alphabetically.
* Attributes: duplicate choice names are flagged in the editor.
* Attributes: deleting a duplicate choice now moves its product assignments, variation combinations and group combinations to the copy you keep (and carries its swatch colour over if the survivor has none). Deleting a choice with no same-name sibling cleans up its orphaned assignments instead of leaving dangling references.
* Attributes: swatch hex colors are accepted with or without the leading "#" and stored in a canonical form.
* Admin: payment-gateway editor resilience improvement (self-healing render boundary).

= 0.2.14 =
* Review-feedback release (round 2). Every global function, hook, option, transient, constant, AJAX action, cron hook, nonce, script handle and localized JavaScript object now carries the `titancart_` / `TITANCART_` prefix (database table names keep their `wp_tc_` prefix — no data migration). Inline scripts and styles are emitted through `wp_add_inline_script()` / `wp_add_inline_style()` with no output buffering. All public REST routes use a named permission callback and the per-order downloads route verifies ownership in its permission callback. Tree-wide input sanitization and output escaping pass. Migration DDL and IN-list queries converted to prepared placeholder patterns. Site Backup (dump/restore) is no longer part of TitanCart Lite. CSV import resolves local images from the WordPress uploads directory. External services section expanded (Google Maps address autocomplete, YouTube/Vimeo video embeds).

= 0.2.13 =
* Review-feedback release: all inline scripts and styles converted to the WordPress enqueue API (payment SDKs are now conditional wp_enqueue_script calls from their provider origins); tree-wide input-sanitization pass (validated client-IP capture, sanitized user-agent/nonce/token reads); REST permission audit — the per-order downloads route now requires login in its permission_callback and the PayPal capture endpoint is bound to the order's secret key; a dedicated External services readme section; upload path now derives solely from wp_upload_dir(); REST URLs built with rest_url(); admin menu moved below Plugins.

= 0.2.12 =
* Internationalization: translator comments added to every translatable string with placeholders, numbered placeholders throughout, and full gettext-extractor compatibility.

= 0.2.11 =
* Security hardening: output escaping tightened across storefront templates and admin notices; JSON-LD structured data is now breakout-proof encoded.
* Code quality: database query annotations completed for coding-standards compliance.

= 0.2.10 =
* Security and standards hardening pass: safer file operations, safe redirects, timezone-correct date handling, locally bundled icon fonts (no CDN), and a gated logging seam.

= 0.2.9 =
* Initial WordPress.org release.

== Upgrade Notice ==

= 0.2.27 =
Adds the per-device image control that TitanCart Prism 0.2.7 needs for its hero. No data changes.

= 0.2.26 =
Recommended for every store on 0.2.25: fixes a slow-request regression caused by an unfinished upgrade step. No data changes.

= 0.2.25 =
Adds the FAQ page manager and site-wide attribute prices (two small schema additions, applied on upgrade), removes Lite's stray Gift Cards page, and fixes the dropdown-attribute label on the product page.

= 0.2.24 =
Safe upgrade, no data changes. Shared-variation attributes set to "Dropdown" now display as a dropdown on the product page.

= 0.2.23 =
Recommended. Per-size pricing for shared variations, copy-to-all when creating separate variations, and every 0.2.22 storefront fix.

= 0.2.22 =
Recommended for every store. Removes hidden quantity-1 price rows that could keep the storefront on a product's old price after a price change; adds attribute pricing and in-place editing for variations.

= 0.2.21 =
Safe upgrade, no data changes. Fixes cart quantity changes and order notes on hosts that strip PUT/PATCH request bodies.

= 0.2.20 =
Safe upgrade, no data changes. Pro sites: this release no longer carries a bundled copy of the Prism theme — your installed Prism in wp-content/themes keeps running and updates itself.

= 0.2.19 =
Settings saves now survive hosts that drop PUT bodies (WordPress Playground included). Pair with Prism 0.2.2 for one-click theme updates. Safe upgrade — no data changes.

= 0.2.18 =
Fresh Prism installs now start on the Apparel preset. Pair with Prism 0.2.1. Safe upgrade — no data changes.

= 0.2.17 =
Adds one-click demo content for the free Prism theme (Theme Options → Demo content). Safe upgrade — adds one table, changes no existing data.

= 0.2.16 =
Fixes the intermittent admin "Page Error" crash. Safe upgrade — no data changes.

= 0.2.15 =
Attribute choice sorting (Manual / A–Z), duplicate-choice warnings and "#"-optional hex colors. Safe upgrade — default behaviour unchanged.

= 0.2.14 =
Prefix and standards release from plugin review feedback. Site Backup is removed from Lite. Recommended for all users.

= 0.2.13 =
Standards and security hardening from plugin review feedback. Recommended for all users.

= 0.2.12 =
Internationalization polish release. Recommended for all users.

= 0.2.11 =
Security hardening release. Recommended for all users.
