=== DPTag Digital Product Passports for WooCommerce ===
Contributors: dppress
Tags: woocommerce, dpp, digital product passport, espr, qr code
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 8.0
Requires Plugins: woocommerce
Stable tag: 0.9.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Create ESPR-ready Digital Product Passports for your WooCommerce products: public passport pages, QR codes and structured data.

== Description ==

The EU Ecodesign for Sustainable Products Regulation (ESPR) is phasing in Digital Product Passports from 2027, starting with batteries and followed by textiles, furniture and more.

DPTag helps WooCommerce merchants prepare today:

* One passport per product, created directly from the product editor
* Guided form with sector templates (textile and furniture), applied automatically per product
* Optional AI autofill: click to let AI read a product and pre-fill the empty passport fields, with a confidence flag and the source snippet on each suggestion (opt-in, free for your first few products, see "External services" below)
* Fibre composition with live percentage validation
* Completeness score for required fields
* Public, mobile-first passport page at /dpp/{id}, no theme dependency, loads fast
* QR code generation (PNG) to print on labels or packaging
* Schema.org JSON-LD structured data on every passport page
* Public REST endpoint for machine-readable passport data
* Passport pages survive product deletion (data longevity by design)

**Note:** the official EU DPP data formats are still being finalised through delegated acts. DPTag is "ESPR-ready": it structures your data along the known requirements and will be updated as official formats are published. It does not by itself constitute legal compliance advice.

= What is free =

All of it, without limits. Publish as many passports as you have products, in every sector template, with the public pages, the QR codes and the structured data. Nothing here is capped, timed, or waiting on a key.

Sectors in particular are never a paid feature: each new sector template ships in this free plugin as it is written.

= DPTag Pro =

DPTag Pro is a separate paid add-on, distributed from https://dptag.com and not from this directory. You never need it to create, publish and print a passport.

It adds tools for a catalogue at scale: multilingual passports across the 24 EU languages, QR codes as SVG for print, bulk CSV and QR export, and a monthly allowance of AI credits.

Those features are not in this plugin, not even disabled: they are code that ships with the add-on. What is here is a page describing them and the hooks the add-on attaches to.

== Installation ==

1. Install and activate WooCommerce.
2. Install and activate DPTag.
3. Edit any product: use the "Digital Product Passport" box to create its passport.
4. Fill in the guided form, publish, download the QR code.

== Frequently Asked Questions ==

= What does "ESPR-ready" actually mean? =

The final data formats are not yet published by the European Commission. DPTag structures your product data along the known ESPR requirements so you are ready when the delegated acts land. It is a preparation and transparency tool, not legal advice.

= Which product categories are supported? =

This version ships Textile & Apparel and Furniture templates. DPTag detects the matching sector from each product's categories, attributes and text, and you can switch it manually in the passport editor. More sectors are planned, and sectors are never a paid feature.

= Does it call external services? =

Only for the optional AI autofill, and only when you click it. Everything else (passport pages, QR codes, structured data) is generated and hosted entirely on your own site, with no network calls. See the "External services" section below for exactly what the AI feature sends and when.

= Is the AI autofill free? =

Your first few products per site are free to try. Beyond that a fill costs one AI credit, because each one is a real call to a service that costs money to run. Credits are on sale to anyone at dptag.com, with no subscription: you buy what your catalogue needs, paste your account key on the AI credits screen, and that is all. DPTag Pro includes a monthly allowance of them. Everything else, creating passports, publishing them, the public pages and the QR codes, is free and unlimited and never touches the network.

= Do I have to trust the AI values? =

No. AI suggestions are proposals you review: each filled field is highlighted (green when confident, amber when it should be double-checked) with the source snippet it relied on. The AI prefers to leave a field empty rather than guess, because a wrong value is worse than a blank one. Nothing is published until you save it.

== Screenshots ==

1. The setup wizard: define store-wide defaults once, avoid thousands of forms.
2. Guided passport form with fibre composition and completeness score.
3. The public passport page, scanned from the QR code.
4. QR code generation from the passport editor.
5. Bulk passport creation from the products list.

== External services ==

DPTag works entirely on your own server, with one exception you control: the optional AI autofill.

When (and only when) you click "Fill with AI" on a passport, or run the AI batch/onboarding, DPTag sends that product's text to the DPTag AI service at https://dptag.com to generate field suggestions.

* What is sent: the product's title, short and long description, product categories and attribute values, together with your site's URL (used to meter the free per-site sample). If you have entered an account key on the AI credits screen, that key goes with the request, so the run is billed to your credit balance instead of the free sample. No customer or order data is ever sent.
* When it is sent: only on your explicit click. DPTag never contacts the service on its own, on a schedule, or in the background.
* Why: the service reads the product text with an AI model and returns proposed values, with a confidence level and the source snippet for each. The service meters usage: a free per-site sample first, then the AI credits on your account if you have entered a key.
* The suggestions are proposals you review and save; nothing is stored remotely as your passport data.
* Sub-processor: to produce the suggestions, the DPTag service passes the product text to Anthropic's Claude API. It is not used to train models. Anthropic's privacy policy: https://www.anthropic.com/legal/privacy
* What the service keeps: the requesting site's domain and a usage counter, so the free sample and the Pro credits can be metered. The product text itself is not stored.

Provider: DPTag (https://dptag.com). Terms: https://dptag.com/terms. Privacy policy: https://dptag.com/privacy.

If you never click the AI feature, DPTag makes no external requests at all.

== Third-party libraries ==

DPTag bundles the QR Code Generator JavaScript library by Kazuhiko Arase (MIT licence, unminified). No data leaves your site.

DPTag bundles two fonts, used only on the public passport page: Inter (Copyright 2016 The Inter Project Authors) and IBM Plex Mono (Copyright 2017 IBM Corp.), both under the SIL Open Font License 1.1. The licence text ships with them in assets/fonts/OFL.txt. They are served from your own domain, never from Google Fonts or any other CDN, so no visitor data reaches a third party and you have nothing extra to disclose.

== Upgrade Notice ==

= 0.9.2 =
AI credits can now be bought without a subscription. Buy what your catalogue needs at dptag.com, paste your account key on the new AI credits screen, and AI autofill runs on that balance. Nothing else changes and nothing new is required.

= 0.9.1 =
Fixes passport links that could answer with your shop front instead of the passport after the update to 0.9.0. If you updated from 0.8.0, install this one: it repairs the links on its own, with nothing to reprint.

= 0.9.0 =
Publishing is no longer capped. DPTag Pro users: update the add-on to 1.4.0 at the same time, as multilingual passports, SVG QR codes and bulk export now live in the add-on itself. Stored passports and translations are untouched.

= 0.8.0 =
Printed QR codes were missing the blank margin a scanner needs, so a code that read fine on screen could fail on a label. Regenerate and reprint any QR already in production. Also fixes a Defaults screen that dropped one sector's values when you saved after switching sectors.

= 0.7.0 =
Fixes two silent data problems: accented characters were stored damaged, and a value containing a double quote could wipe a passport's fields with no error. If a passport of yours reads blank or shows mangled accents, re-enter it once after updating and it will save correctly from then on.

== Changelog ==

= 0.9.2 =
* AI credits no longer need a subscription. They are on sale to anyone at dptag.com, and a new "AI credits" screen is where you paste your account key so a run is billed to that balance. Buying what your catalogue actually needs beats a monthly fee at both ends: eighty products and three thousand products are not the same purchase.
* The key is optional and gates nothing. Without one the plugin behaves exactly as before, including the free AI allowance every site gets, and everything that is not AI stays free and unlimited either way.
* The AI meter shows your credit balance once a key is set, instead of a free allowance you are no longer spending.

= 0.9.1 =
* Fixed: after updating from 0.8.0, every public passport link could answer with the shop front page instead of the passport. The URL rule WordPress had stored still pointed at the name the plugin used before it was renamed, and updating a plugin does not rebuild those rules. They are now rebuilt automatically after any update, so the links, and the QR codes printed on your labels, come back on their own.
* The passport post type is now named `dptag_passport` instead of `dpp_passport`. A post type name is shared across every plugin on a site, and `dpp` is the generic acronym of the regulation itself, so it was the name a second Digital Product Passport plugin was most likely to claim as well. Your existing passports are renamed in place on update: same passports, same IDs, same UUIDs, so every QR code already printed on a label keeps resolving to the same page.
* Escaping moved to the point of output on the two places that had it one call earlier: the AI meter and the public page's inline stylesheet. Nothing was exploitable, and nothing changes on screen; escaping where the value is printed is what keeps it true when the code around it changes.

= 0.9.0 =
* Publishing is unlimited. The free plan used to stop at 10 published passports and quietly save the eleventh as a draft; that cap is gone, along with the notices that announced it. Whatever your catalogue holds, you can publish.
* Multilingual passports, SVG QR downloads and bulk CSV/QR export now ship inside the DPTag Pro add-on instead of sitting in this plugin behind a licence check. Nothing here is locked any more: what this plugin contains, it does. If you subscribe, update the add-on to 1.4.0 and the screens come back exactly where they were. Translations already stored keep working and keep showing on the public passport page, which reads them whether or not the add-on is installed.
* The public passport page's stylesheet moved into a file of its own and is enqueued rather than printed inline by hand. It is still delivered inside the page, so a passport is still one request: on a phone in front of a shelf, that matters more than the few kilobytes a cached file might have saved.
* The "Upgrade to Pro" menu item is no longer painted gold with a star on every screen of your admin. It is still in the menu, just no longer shouting from someone else's furniture.
* Hardened: the AI meter's markup is now filtered through an allow-list before display, and the passport REST listing re-checks every row against your rights instead of trusting a single capability, so a contributor no longer sees other people's drafts.

= 0.8.0 =
* Fixed: the store Defaults screen could throw away your work. The sector pills (Textile, Furniture) looked like tabs but were separate pages, so filling in one sector, switching to the other and saving kept only the sector on screen and silently dropped the rest. Every sector now lives in one form and a single Save writes them all. Same fix on the per-category defaults, where switching sectors also lost WordPress's own unsaved term fields.
* Fixed: printed QR codes were unreliable. The generated code had no quiet zone, the blank margin a scanner needs to find the code's edges, so it read fine on screen and then failed once printed next to other ink on a label. Codes now carry the standard 4-module margin, verified by decoding them back at 600, 300, 180 and 120 pixels. Regenerate any QR code already in production.
* The QR code is drawn in DPTag indigo with rounded data modules, a discreet brand touch on a code that stays fully standard and scannable everywhere. Nothing is painted over it: it goes on your product label, not ours.
* Multilingual passports (DPTag Pro). Under ESPR the passport speaks the market's language, not the brand's. A passport can now carry translations of its written fields across the 24 EU languages, typed by you or produced by AI, while figures, materials, country of origin and certifications stay shared. The public page honours ?lang, shows a native language selector and declares hreflang alternates. The page's own wording, section headings and field names, is translated into the 24 languages and follows the language on screen, with nothing to install: a passport reads the same whether the shop runs in French, Polish or English. The product name can be translated too, and is optional: leave it empty and the page keeps the name printed on your label, in every language. Existing passports are untouched: a translation is stored alongside the original, which stays the source of truth.
* Language suggestions drawn from your actual sales (DPTag Pro). Rather than asking you to guess, DPTag reads a bounded sample of recent WooCommerce orders, keeps the EU destinations and shows the markets you ship to, with one-click buttons for the languages you have not covered yet. It reads your own shop data, with no network call. It stays advisory: a country is not a language, and each member state sets its own rule.
* SVG QR codes and bulk export (DPTag Pro). The QR code downloads as SVG for print at any size, and a new Export screen produces a CSV of every passport (one sheet, its columns the union of every template's fields) plus a ZIP of every QR code. The CSV is streamed in batches so it stays within the memory of an entry-level shared host.
* AI translation runs on a smaller model and is included in Pro under fair use, instead of costing an AI credit per language. Rendering prose you have already validated into another language is an easier job than reading a product from scratch, and should not be priced like one.
* You can see how many free AI passports you have left. The first few AI-generated passports on a site are free, but nothing on screen said so or counted down. Every AI surface now shows a meter, updated live during a bulk run, so you can watch the free ones spend no credits.
* The AI now tells you what it left alone. AI autofill only ever fills empty fields, so a value already placed by your defaults wins. That was true but invisible: the result notice reports how many already-filled fields it kept, and the AI card states the rule before you click.
* New, and off by default: let the AI revisit your store-wide defaults. A single default applied to a whole catalogue (one country of origin, say) can be wrong on a given product, and until now it blocked the AI from ever proposing the correction. With the option on, the AI may propose a replacement for a value that came only from a store-wide default and has not been edited since. Category defaults and product attributes are per-product facts and are never revisited. Proposals stay proposals: you review them, and Dismiss puts the original back.
* Bulk AI creation shows that it is working. An AI call takes several seconds, so the progress bar used to sit frozen at "0 / N" with no sign of life. It now carries a sweep and a spinner while a run is live, and the passports list reloads when the run ends so the new passports actually appear instead of being announced but absent.
* Bulk AI creation counts what you care about. A run that created three passports but found nothing new to add to one of them used to report "2 filled". It now counts the passports it produced, and only offers products with no passport at all, so the panel clears after a run instead of re-offering work that is already done. Topping up an existing passport is what the per-passport "Fill with AI" button is for.
* The AI panel no longer vanishes once every product has a passport. It took the meter with it, so there was no way to check where you stand on free samples or credits from that screen. A slim version stays, without the run button.
* Deleting the plugin no longer deletes your passports. The uninstall routine used to erase them, and a passport is not the plugin's data: its UUID is the address printed on the QR codes already sewn into your garments, and recreating a catalogue mints new ones, so every printed code would point at a dead page for good. Uninstalling now removes only DPTag's own state, two caches, the wizard flag and a dismissed hint, and leaves your passports, your store and category defaults and your public passport pages standing. To erase them, select them in the passports list and move them to the trash, where the action is visible, immediate and reversible.
* Security hardening ahead of the wordpress.org submission. The public page's JSON-LD block now escapes angle brackets and ampersands, closing a route for product text to break out of the script tag. The AI onboarding endpoint requires the same capability as the button that offers it, so a Contributor cannot call it in a loop and burn your AI credits.
* Fixed: the passport panel drifted to the bottom of the product editor for anyone who had ever reordered their boxes. WordPress remembers a per-user box order and ignores declared priority once it exists, adding any box missing from that order at the very end. The panel now slots itself in just after the Publish box when it is absent from the saved order, and leaves it where you put it when you have placed it deliberately.
* Fixed: the QR code in the passport editor stopped appearing. Sharing the QR renderer with the products list moved it into its own file, which was queued on the list but not on the editor, and the editor failed silently: an empty frame and no error anywhere.
* The public passport preview opens wider, 480 pixels instead of 390. The passport card carries its own page margins, so at the narrowest phone width it filled the frame edge to edge and read as a cramped page rather than a phone.
* Keyboard focus rings are back where they belong. WordPress draws its focus outline on mouse clicks too, which put a heavy double border on every link you clicked. DPTag screens now use :focus-visible, so the ring appears for keyboard navigation and stays out of the way of the mouse. It is replaced, never removed.
* The QR dialog's URL is a link that opens in a new tab, rather than an address to retype.
* The DPTag section is gone from the WooCommerce product category editor. A sector picker on a single category was confusing, and it duplicated the setup wizard's "composition per category" step, which is now the one place to set it. Your existing per-category values are kept, and still take priority over store-wide defaults.
* Wording: the box in the product editor is called "Digital passport", and the wizard's automatic card no longer presents creating and filling a passport as two steps, since the AI does both at once.

= 0.7.0 =
* Fixed: accented characters were stored damaged. A repairability note reading "emboîtement" was served as "embou00eetement" on the public passport page. The post and metadata APIs strip one level of slashes from everything they store, which ate the escapes in the saved JSON. Every write now compensates, so accents survive the round trip.
* Fixed: a passport could silently lose all of its data. Same cause, worse effect: a value containing a double quote broke the stored JSON outright, so the passport read back empty with no error anywhere. If a passport of yours looks blank, re-enter it and it will now save correctly.
* Fixed: AI autofill added an empty material row above the materials it found.
* Fixed: clicking "Fill empty fields with AI" gave no sign it was working, and clicking again during the wait spent a second AI credit on the same product. The button now shows it is running and ignores further clicks.
* Fixed: the AI restated the same fact in several fields whose scopes overlap, so a furniture passport could carry the same sentence, reworded, under both "Repairability" and "Disassembly instructions". It is now told to give each fact one home and leave the rest empty.
* The public passport page is set in Inter and IBM Plex Mono, the same faces as dptag.com, so a passport looks the same on every phone instead of changing with the device. The fonts ship with the plugin and are served from your own domain: no request to Google Fonts, nothing new to disclose to your visitors.
* Accessibility: the page's labels, section headings and footer were grey enough to fail WCAG AA contrast (3.31 against a 4.5 minimum) at every size they are used. Darkened to 5.15. This is a document meant to be read, printed and photocopied.
* The passport page reads as a document rather than a dashboard: each field's label now leads and its value follows as body text, short facts sit together in columns, and long notes take the full width instead of leaving a hole beside a two-word answer.
* The fibre composition bar takes its colours from the card's own top border, one per material, spread so neighbouring segments stay tellable apart in greyscale, on a photocopy or with colour blindness.
* A corrected passport is no longer stale. The page used to tell browsers to keep it for an hour, which cannot be undone once sent, so fixing a wrong value left the old one on screen for anyone who had already scanned the code. Browsers now check for a new version on every view.
* "Country of origin" suggests country names as you type. It stays a free text field: type whatever the product needs.
* The passports list no longer shows two competing "create your passports" buttons when it is empty.
* Fixed: the passport column fell out of the products list. On a WooCommerce table already carrying SKU, stock, price, categories, tags and brands, the column had no declared width, so the browser squeezed it until the header broke into a vertical D/P/P and the status pill sat outside the table.
* The public passport page draws a rule only where a section starts. A separator between two fields inside a section used to be drawn exactly like the one between two sections, so a section of three fields read as three sections. Spacing separates fields now, which is all that boundary ever needed.
* Fixed: the public passport page printed "Composition" twice when a passport filled the Substances of concern field. The materials bar is rendered above as the signature element, and the loop below skipped the materials field but not its group, so the rest of that group printed a second identical heading. Those fields now sit under the heading already on screen.
* Fixed: after deactivating the plugin, a passport URL returned the shop home page at HTTP 200 instead of a 404. Deactivation flushed the rewrite rules while the plugin was still loaded, which wrote its own /dpp/ rule straight back into the database; the orphaned rule then matched but resolved to nothing. Deactivation now lets WordPress rebuild the rules cleanly, so old passport links correctly 404.
* A "View" link in the passports list row actions, opening the public page in a new tab. WordPress offers none of its own, since the passport has no permalink: its page lives on the /dpp/ rewrite.
* The product editor's passport panel now sits directly under the Publish box, and on a published passport its actions are one full-width row: edit, preview, QR, open. It used to sit above Publish, so its button landed where Update is expected and got clicked by mistake; and reaching a product's QR meant opening its passport first.
* Three shortcuts under the passport status in the products list: edit it, preview its public page at phone width, or show its QR code with a PNG download. The preview and QR appear on published passports only, since the public page does not answer until then.
* The products list column is called "Passport" and the bulk action "Create product passports", instead of leading with the DPP acronym. It means nothing to a merchant on day one, and it sat between column headers that are all plain words.
* The setup wizard's data-entry steps now offer a way back to the AI, next to "Skip this step". The welcome step already asked whether you wanted AI or manual, but nobody regrets typing until they have started, and until now there was no way out once they had.
* The setup wizard now says which product sector it is setting up. Steps 2 and 3 show the field set of your catalogue's main sector and save for that sector alone, but nothing said so, and the text claimed the values applied to "your whole catalogue" even when a second sector had been detected right below.

= 0.6.2 =
* The "Let AI create your passports" panels (wizard, passports list, products list) now show one consistent count everywhere: the products the AI still has to work on (no passport yet, or a passport with empty fields). Complete passports are excluded, so the number never overstates what a run will fill.
* Wording: the metered AI unit is called an "AI credit" again (1 credit fills one product), so it reads clearly next to "unlimited passports". Passports (the pages) stay free and unlimited; only AI filling uses credits.

= 0.6.1 =
* Added an extension point below the "Let AI create your passports" panels so DPTag Pro can show a per-catalogue calculator (how many products your run will fill, what your plan covers, and the cost of the rest). No effect and no network call without the Pro add-on.

= 0.6.0 =
* Optional AI autofill (opt-in, disclosed): click "Fill with AI" on a passport, or use the AI batch and the setup wizard's "Automatic" onboarding, to let AI read a product and pre-fill its empty fields. Each suggestion is highlighted by confidence (green/amber) and shows the source snippet; the AI leaves a field empty rather than guess. Free for your first few products per site; a larger catalogue uses DPTag Pro AI credits. The only outbound request the plugin ever makes, and only on your click (see "External services").
* New "Upgrade to Pro" page explaining what DPTag Pro adds (unlimited passports, monthly AI credits, SVG QR, bulk export, multilingual passports).

= 0.5.0 =
* Multi-sector passports: added a Furniture template alongside Textile. Each passport adapts its field set to the product's sector, and sectors are never gated (they ship in the free plugin).
* Automatic sector detection from WooCommerce categories, attribute names and product title/description. Fully local, no network calls. A sector selector in the passport editor lets you override the guess.
* Per-sector defaults: store-wide defaults (DPTag → Defaults) and per-category defaults are now kept separately for each sector, with transparent migration of existing single-sector defaults.
* Setup wizard now detects your catalogue's dominant sector and targets it, listing the other sectors it found.

= 0.4.0 =
* First public release (versions 0.1.0-0.3.x were internal pre-release iterations; the entries below trace the main milestones).
* Redesigned public passport page: refined "textile label" look, indigo-to-gold accent, product thumbnail beside the title, fibre composition bar as the signature element. Still self-contained (system fonts, inline SVG, no network calls).
* Passport editor now shows an "unlimited passports" state instead of a remaining count when a higher plan lifts the publish limit.
* Harmonised the whole admin with the "textile label" identity: passport editor metaboxes, QR box, Defaults screen, product metabox and DPP column, and the setup wizard.
* Passport editor and Defaults screen now group fields into collapsible sections; the editor flags sections with missing required fields.
* Product list shows a dismissible hint to the bulk "Create DPP passports" action; the empty passports list invites the setup wizard.

= 0.3.0 =
* Setup wizard on activation: store defaults, per-category composition, bulk creation in batches.
* Redesigned wizard UI.

= 0.2.0 =
* Store-wide passport defaults (DPTag → Defaults).
* Per-category defaults on product category edit screens.
* Automatic pre-fill from existing product attributes (composition, country of origin, care, certifications) with composition parsing ("80% cotton, 20% polyester").
* Bulk action "Create DPP passports" in the products list.

= 0.1.0 =
* Initial release: textile template, passport pages, QR codes, JSON-LD, REST API.
