== Changelog ==

Complete release history for Polski for WooCommerce. The plugin page on WordPress.org lists only the most recent releases; this file keeps the full record.

= 1.31.2 =
* Fixed: an order given one of the withdrawal statuses vanished from WooCommerce - Orders. The three statuses were 21 to 23 characters long and an order status is stored in a 20-character column, so each one was cut short on the way into the database and the order ended up carrying a status that is registered nowhere. It was never lost: it stayed in the database, opened normally from its own URL, and came back on the list as soon as a standard status was set. The statuses are now short enough to store, and updating rewrites the ones already saved. Reported by strid3rr on the support forum.
* Fixed: the withdrawal button and the complaint / return link appeared on the order confirmation screen, straight after checkout. WooCommerce 10.9 began rendering My Account order actions there as well; both links belong on My Account - Orders, which is where the documentation puts them. Reported by strid3rr on the support forum.

= 1.31.1 =
* Fixed: switching the NIP module off left the NIP field on checkout. Two services could add it, and the second one defaulted to on from a setting no screen writes, so the switch a merchant can actually see only ever worked in one direction. The field now has a single owner, the NIP module, on both the block and the classic checkout. Reported by czester on the support forum.

= 1.31.0 =
* Added: VAT invoices in the free plugin. The Invoices module adds an Issue invoice button to the order screen, numbers invoices per year (FV/1/2026, restarting each January), shows both parties with their VAT IDs, lists each line with its own rate, and groups VAT by rate. Shipping and fees are invoiced too.
* Added: an Invoice link on the customer's order in My Account. The document opens through a link carrying a token derived from the invoice, so it works from an email without a login and cannot be reached by guessing an id.
* Added: the document is laid out for A4 and prints cleanly. No PDF engine is bundled: a usable one is tens of megabytes, and every browser already prints to PDF.
* Note: an issued invoice is frozen at the moment it is issued, so a later edit to the order does not rewrite it, and issuing twice returns the existing invoice rather than allocating a second number. The number carries a UNIQUE key, which is what actually holds when two admins press the button at the same moment.

= 1.30.8 =
* Fixed: the NIP field never appeared on the block checkout. Polski boots on `init` priority 0, by which point WooCommerce has already fired `woocommerce_init`, so the three services that registered their block checkout fields on that action registered them into an event that had already passed. Affected the NIP lookup module, the B2B checkout fields and, in PRO, the invoice request field.
* Fixed: legal checkboxes could be switched on but never off. Two handlers were attached to the same admin-post action; the one that won only wrote back the fields present in the request, and an unticked checkbox is absent from a form submission, so every saved state was a merge that could only ever add. The losing handler was the correct one. There is now a single save path, and it also stops stripping the link markup out of the Terms and Privacy labels.
* Fixed: the order button label had no effect on the block checkout. That button is rendered by React and its label resolved through WooCommerce's own checkout filter, so the PHP `gettext` filter Polski used could never reach it. It now registers the supported `placeOrderButtonLabel` filter instead. The classic checkout is unchanged.
* Fixed: the NIP field was registered twice when both the NIP lookup module and the B2B checkout fields were on, which WooCommerce rejects. The lookup module now owns the field.
* Added: `tests/boot-timing-check.php`, run as the first preflight step. It fails on both shapes above, neither of which produces an error, a warning or a failing assertion.

= 1.30.7 =
* Fixed: the Polski icon in the admin menu still sat low on a narrow screen and when the menu is collapsed to icons. WordPress shrinks that row from 34 to 30 pixels in both cases and the plugin was still centring the icon in the taller one. 1.30.3 fixed the ordinary sidebar; this fixes the other two.

= 1.30.6 =
* Fixed: a shop manager could open the withdrawal settings screen but not save it. The menu was available to anyone who manages WooCommerce, while saving was still restricted to a full administrator, so pressing Save ended in a permissions error. Both now use the same permission.
* Fixed: changelog.txt, the file that keeps the full release history inside the plugin, was missing the last four releases.

= 1.30.5 =
* Fixed: a percent sign in the guest form's intro text, added in 1.30.4, corrupted the sentence on the public page. Writing something as ordinary as "Zwracamy 100% ceny" produced "Zwracamy 100" followed by an invisible byte and the rest of the line, because the text was passed through a formatter that reads a percent as a formatting instruction. The intro now uses {company} and {days} and prints everything else exactly as typed, percent signs included. If you already saved an intro containing a percent, it will render correctly after this update with no change on your side.
* Fixed: the plugin reported its own version as 1.29.7 while being 1.30.x. That number is shown on the plugin's admin page and is used to version stylesheets and scripts, so an admin who had already loaded the old files kept them after updating, which is why the menu-icon fix in 1.30.3 may not have appeared for you. It is also the value the plugin compares against when deciding whether to run an upgrade routine. The release script had been silently failing to update it since 1.29.7.

= 1.30.4 =
* Added: the guest withdrawal form's wording is now editable under Withdrawal settings, in a Guest form wording section: the heading, the intro paragraph, the two field labels and the submit button. Asked for on the support forum. The texts on the My Account side were already editable and these were not, which was an inconsistency rather than a decision. Leave a field empty and the built-in wording is used exactly as before, so nothing changes for a shop that does not open the screen. The intro accepts %1$s for your company name and %2$d for the withdrawal period, and prints your text as written if you leave them out.

= 1.30.3 =
* Fixed: the Polski icon in the admin menu sat lower than every other icon in the sidebar, and jumped into place only while the pointer was over it. WordPress puts vertical padding on that element and the plugin's own styling cleared it only in the hover state, so the icon was misaligned for as long as you were not pointing at it.

= 1.30.2 =
* Declared compatibility with WooCommerce 11.0.

= 1.30.1 =
* The Polish catalogue is bundled again, on purpose. WordPress.org builds its language packs from the strings in the released package, so a release that changes source strings always lands before translate.wordpress.org has seen the new ones, and this release changes about 520 of them. Without the bundled copy a Polish shop would read an English interface until the translations were re-imported. WordPress still prefers the language pack wherever it has a string, so nothing overrides a translator.
* Fixed the PRO promo on the settings screen quoting a price in PLN. PRO is priced and charged in EUR, so an admin on a Polish site was shown a zloty amount and then billed in euro, and the zloty figure was a fixed conversion that drifted from the real charge as the rate moved. The promo now shows the euro price that is actually taken.
* Rebuilt the bundled language catalogues from translate.wordpress.org rather than from the copies in the repository. Those copies had fallen behind: Polish was missing 43 strings that translators had already done, and disagreed with them on another 52. Polish and Czech are now complete.
* Fixed the withdrawal information block printing its heading twice. It rendered a title of its own directly above the first statutory heading from Annex I to Directive 2011/83/EU, so "Right of withdrawal" appeared on two lines in a row. The two statutory headings are now the only headings, both at the same level as the model form's.

= 1.30.0 =
* The plugin's source strings are now English. About 520 of them were written in Polish, which is how the plugin started, but WordPress.org expects an English source: every other language on translate.wordpress.org was being translated out of Polish rather than out of the original. Nothing changes on a Polish shop, because each of those strings now carries its old Polish wording as the Polish translation. Shops running another language get translations made from English for the first time.
* Along the way, a handful of strings that said the same thing in two different ways were consolidated, so the same label no longer appears as two entries to translate.

= 1.29.8 =
* The package no longer bundles translation catalogues. Polish, Belarusian, Czech, Slovak and Chinese all have WordPress.org language packs built from translate.wordpress.org, so the bundled copies were duplicates of files WordPress already installs on its own, and they added about a megabyte to every download. Nothing changes for those languages. Spanish is the exception: there is no Spanish translation on translate.wordpress.org and therefore no Spanish language pack, so the Spanish interface falls back to English.
* Housekeeping: the release build refuses to produce a package that carries translation catalogues, development files or editor backups, or whose plugin header and readme disagree about the version or the WordPress version tested. The 1.29.7 build was one manual check away from being uploaded with a mismatched header.

= 1.29.7 =
* Declared compatibility with WordPress 7.1.
* Fix: the withdrawal confirmation email now actually reaches the customer. WooCommerce builds its email objects only when something asks for them, and nothing did on a storefront request, so the confirmation had no listener attached and was never sent even though the declaration itself was saved. That is why 1.29.5 did not settle it. The same wiring now also covers the guest declaration form, the REST endpoint, the double opt-in email and the completed and rejected notices.

= 1.29.6 =
* Fix: resolved a TypeError fatal error on WooCommerce -> Reports when opening sales and refund reports due to non-array statuses passed through the woocommerce_reports_order_statuses filter.
* Fix: legal checkboxes module toggle is now properly honored on modern WooCommerce block checkout; disabling the module cleanly removes all additional consent checkboxes and restores standard WooCommerce terms behavior.
* Fix: added WooCommerce 8.6+ Additional Checkout Fields API integration for the NIP lookup module, enabling the NIP field and validation on modern block checkout pages.
* Fix: the checkout order button text now defaults to statutory "Zamawiam z obowiązkiem zapłaty" when the module is enabled without a custom override, and translates place order button text across both classic and block checkout.

= 1.29.5 =
* Fix: resolved a TypeError fatal error occurring when filing a withdrawal declaration on the storefront due to hook argument type mismatch in the AI withdrawal reason classifier; confirmation email is now delivered reliably.

= 1.29.4 =
* Fix: changed allergen seeding names in gettext calls to standard English source strings with bundled Polish translations, ensuring GlotPress translation catalogs on translate.wordpress.org remain 100% complete and valid across all locales.

= 1.29.3 =
* Fix: resolved a fatal error occurring when filing a withdrawal declaration or viewing the withdrawals list in WP Admin due to mismatched template variables and date formatting on DateTimeImmutable instances; email confirmation is now delivered reliably.

= 1.29.2 =
* Fix: restored automatic NIP verification and company auto-fill from GUS REGON on checkout; fixed script initialization for custom themes (e.g. Divi) and replaced PHP SoapClient with robust SOAP 1.2 HTTP transport to resolve GUS XOP/MTOM multipart parsing.

= 1.29.1 =
* Corrected the PRO pricing note. It said the amount is shown in PLN at checkout, which is not true: Polski PRO is priced and charged in EUR. The note now says so, in English, Polish, German and Spanish.

= 1.29.0 =
* **The Food module now works.** It never did. The service checked a setting that the plugin seeds as off and never writes, so the food block on the product page was invisible on every shop no matter what the Food module toggle said. It now follows the toggle, which is the switch you can actually reach. Enter ingredients, allergens, nutrition, Nutri-Score or alcohol content, switch the module on, and they appear.
* The other half of the same bug: the food shortcodes and the Elementor food widgets ignored both switches and rendered regardless. They now follow the module too. So that nothing disappears from a shop relying on them, this update switches the Food module on automatically wherever food data already exists: any product with ingredients, nutrition, Nutri-Score, alcohol content, origin or net quantity filled in, or any product tagged with an allergen.
* Double opt-in now follows its module toggle as well as its own setting; previously the toggle did nothing. Shops that already had double opt-in switched on keep it, because the module is enabled for them automatically, so no account waiting for verification suddenly becomes able to log in.
* Environmental claim fields in the product editor now follow the Anti-greenwashing module. When the module is off the plugin now leaves stored claims alone instead of clearing them the next time you save the product. Shops with claims already entered get the module switched on automatically.

= 1.28.0 =
* Six module toggles now do what they say. An audit of all 91 modules found ten with no enabled-check anywhere in the code, meaning the switch was decorative and the feature ran regardless. Fixed in this release: Checkout button, Consent logging, Legal pages, Email attachments, Plugin data and the store audit's environmental-claims check.
* The most consequential of those: **Consent logging kept recording after you switched it off.** Every order still wrote a row with the shopper's IP address, browser user agent and timestamp. If you had that module off, personal data was being collected against your setting. It now stops when the module is off. Rows already stored are left alone; delete them from the consent records screen if you want them gone.
* Checkout button: switching the module off now really restores WooCommerce's own "Place order" wording, on the classic, block and multi-step checkouts alike.
* Email attachments: switching the module off now really stops the legal documents being attached to customer emails. Worth knowing before you switch it off.
* Legal pages: switching the module off stops new pages being generated. Pages you already have stay published and keep being used everywhere else in the plugin. The module description said "Off until enabled", which was not what happened; it now describes the real behaviour.
* Plugin data: uninstall now honours the module. With it off, uninstalling leaves your data in place regardless of the delete setting.
* Fixed the store audit reporting a warning for environmental claims even on stores that had the module switched on. It was checking a module id that does not exist.
* Raised the minimum WordPress version from 6.4 to 6.9. This matches what already had to be true: WooCommerce 10.8 raised its own WordPress minimum to 6.9, and this plugin requires WooCommerce, so a store on WordPress 6.4 could not be running a supported WooCommerce anyway. The old header promised a compatibility that did not exist.
* Development dependency: WooCommerce stubs aligned to 10.9.

= 1.27.1 =
* The nutrition table listed energy twice with both rows labelled "Energy", because the regulation asks for it in kilojoules and in kilocalories. The rows now read "Energy (kJ)" and "Energy (kcal)".

= 1.27.0 =
* New module, Consumer information: the product page can carry the reminder that the statutory guarantee of conformity applies, plus per-product fields for a commercial guarantee of durability, the period of free software updates for goods with digital elements, and repair information. This is the pre-contractual information Directive (EU) 2024/825 requires from 27 September 2026. Off by default. The harmonised label artwork for the durability guarantee comes from a separate implementing act, so the module renders plain labelled rows for now.
* Fixed: the nutrition table could never be filled in. The stored nutrition meta had two readers expecting incompatible shapes and nothing that wrote it, so the table never appeared and the nutrition data was always missing from structured data. Nutrition values now import and export through the WooCommerce product CSV, like ingredients and the other food fields, using the form energy_kcal:250|fat:12.3|salt:0.9.

= 1.26.0 =
* The fourteen allergens of Annex II to Regulation (EU) 1169/2011 are now seeded on update, so the allergen field is usable straight away instead of starting empty. Terms you already created keep their own names; matching is by slug.

= 1.25.4 =
* Declared compatibility with WooCommerce 10.9.

= 1.25.3 =
* Security: guest product questions now await moderation instead of auto-publishing, and Q&A voting is restricted to valid answers.

= 1.25.2 =
* Translation quality pass: corrected Polish, German and Spanish (product names kept in English, legal withdrawal terminology, WooCommerce glossary and grammar fixes).

= 1.25.1 =
* Documentation: readme links are now labelled links.

= 1.25.0 =
* Added AI transparency support for the AI Act (art. 50): AI-classified withdrawal reasons are now labelled as such, and a new "Label AI-generated content" option (on by default) discloses product copy generated by the Pro AI description generator on the storefront.

= 1.24.12 =
* Fixed low-contrast headings on the admin settings screen under an OS dark-mode preference.

= 1.24.11 =
* Added a Free vs PRO overview to the readme.

= 1.24.10 =
* Added bundled Polish, German and Spanish translations for the plugin interface.

= 1.24.9 =
* Added a dashboard overview of PRO features (polski PRO).

= 1.24.8 =
* Accessibility: the social-proof toast is now keyboard-dismissable, respects reduced motion, and meets AA contrast.
* Admin: a Polish flag is shown on the Polski row in the plugins list.
* Added a WordPress Playground blueprint so the plugin can be tried via the wp.org Live Preview.
* Translations: only the Polish translation is bundled; other locales come from the WordPress.org language packs.
* Housekeeping: Plugin Check code annotations; release package no longer bundles dev tools.

= 1.24.7 =
* Housekeeping: stop bundling machine-generated translations (Polish is kept); other languages now come from the WordPress.org language packs. Also keep build artifacts out of the released package. No functional changes.

= 1.24.6 =
* Fix: a module switched off in Polski > Modules no longer renders anything on the storefront. Previously some features left a non-working button or stray markup behind when disabled (quick view, compare, wishlist, unit price, "from" price, the Omnibus lowest-price note, the VAT and shipping notices, delivery time, manufacturer, badges, the withdrawal links, the dispute-resolution notice, and GPSR safety details).

= 1.24.5 =
* Fix: the VAT notice under the price no longer shows a doubled percent sign ("23%%" → "23%").
* Fix: the shipping-costs notice no longer runs into the VAT notice ("VATzzgl." → proper spacing), including in page builders that don't load the plugin stylesheet.
* Fix: the default Polish shipping-costs label is now "plus koszty wysyłki" (previously an untranslated German "zzgl. kosztów wysyłki").

= 1.24.4 =
* New blocks: product-data blocks for block themes and the editor - Unit Price, Delivery Time, Lowest Price (Omnibus), Tax Information, Shipping Costs, Manufacturer, Safety Instructions, Safety Documents, Power Supply, Defect Description, Nutrition Values, Allergens, Ingredients, Nutri-Score, Food Information and Product Safety Information (GPSR) - all in the "Polski" category. Each one displays the matching product data and shows nothing outside a product context. This brings the block editor to parity with the Polski widgets for Elementor.

= 1.24.3 =
* New blocks: DSA Report Form, Dispute Resolution (ODR) Information, Small-Taxpayer VAT Exemption Information and Available Payment Methods are now available as blocks (in the "Polski" category), so they can be placed on any page without remembering a shortcode. Each one displays nothing until the matching feature is configured.

= 1.24.2 =
* New: all Polski blocks are now grouped in the block editor under a separate "Polski" category, and block metadata is registered from block.json files, so the blocks are correctly visible and easier to find.
* Fix: storefront blocks - AJAX search, AJAX filters and the product slider - did not register on installed pages. They now register correctly and appear in the editor.

= 1.24.1 =
* Fix: the gallery and zoom lightbox could stay on screen as a dark overlay if the theme forced its own display value. The closed state is now always hidden.
* Hardening: the popup and quick-view overlays also force the hidden state, so a theme should not keep a closed overlay on screen.

= 1.24.0 =
* New: full support for the WooCommerce block checkout. Consent checkboxes, the digital-content consent and custom checkout fields render, validate and save in both the block and classic checkout.
* New: product information, including the lowest price from 30 days, the unit price and the delivery time, appears in the block cart and checkout.
* Security: hardened rate-limit handling on the guest withdrawal path and improved IPv6 address anonymisation in the consent log.
* Fix: uninstall removes all plugin tables, database migrations run in the correct order, and the Omnibus lowest-price window no longer collapses to the current price for an empty period.

= 1.23.2 =
* Improvement: the setup wizard is now a guided multi-step process: company, legal, taxes and OSS, checkout, finish. It collects company data, enables the needed legal modules and helps configure taxes and checkout. Optional steps can be skipped, and finishing does not disable modules you already use.

= 1.23.1 =
* Translations: completed the bundled translations for German, Czech, Slovak, Ukrainian, Lithuanian, Belarusian and Simplified Chinese, including the text of the new setup wizard and module search and sorting.

= 1.23.0 =
* New: the setup wizard. A new card suggests ready-made scenarios such as a Polish legal baseline, food and grocery, digital products, B2B and wholesale, fashion and conversion growth. The wizard only enables modules, it does not disable existing settings.

= 1.22.7 =
* Fix: the Polski admin menu icon no longer shifts on hover and in the active state.

= 1.22.6 =
* New: the modules screen now has instant search by name and description and sorting: grouped, alphabetical or enabled first. Without reloading the page.

= 1.22.5 =
* Fix: removed a TypeError fatal error that could occur on order queries, including on the WooCommerce orders screen, when the withdrawal query helper received a pagination object instead of an array.

= 1.22.4 =
* New: the BDO number module. Enter a BDO number and display it with the [polski_bdo] shortcode or the BDO number block, for example in the footer. The company identification block can also include the BDO number.

= 1.22.3 =
* Admin: merged five separate settings screens into one tabbed screen, and moved withdrawals, the consent log, CRA incidents, SBOM, the complaint template and GDPR training documents into a reports and tools centre.
* Admin: split the module list into groups and added tooltips to each module. Action links are dimmed when a module is disabled.
* Fix: the Polski menu icon is now centred relative to its label.
* Translations: refreshed and recompiled all bundled language catalogs after the settings and menu changes.
* Documentation: updated the documentation and plugin-page links on plogins.com.

= 1.22.2 =
* Translations: translated all interface strings added in 1.21.0 and 1.22.0 (Consent Manager, Tag Manager, AI Bridge, Custom Integrations, Safe Fonts, and Custom Triggers) into every bundled locale (Polish, German, Czech, Slovak, Ukrainian, Lithuanian, Belarusian, Simplified Chinese). Recompiled the binary and JavaScript translation files.

= 1.22.1 =
* Fixed (privacy): the shop business-identification ability and the withdrawal annex documents no longer fall back to the site administrator email when no public contact email is configured. They now return an empty email instead, so the administrator address is never exposed through publicly readable output.

= 1.22.0 =
* New: Consent Manager - a native cookie-consent banner with categories (necessary, preferences, analytics, marketing), Google Consent Mode v2 (signals default to denied and update when the visitor chooses), consent-gated script loading, and a records-of-consent log with CSV export. Module is off by default.
* New: unified Tag Manager - load common marketing and analytics tags (such as Meta Pixel, TikTok, Microsoft Ads, Clarity, LinkedIn, Pinterest, X, Matomo, Plausible, PostHog, Hotjar, Inspectlet, Crazy Egg, Simple Analytics) by entering your own IDs. Every tag is loaded only after the matching consent category is granted. Module is off by default.
* New: Custom Integrations - add your own header or footer snippets, each assigned to a consent category so it runs only after that category is granted.
* New: Safe Fonts - help reduce layout shift and defer Google Fonts, with an option to hold the fonts stylesheet until the chosen consent category is granted.
* New: Custom Triggers - push custom data-layer events on page or click conditions, optionally gated by consent.
* All new modules are off by default and integrate with the Consent Manager.

= 1.21.0 =
* New: AI Bridge - exposes read-only store information to AI assistants and agents through the WordPress Abilities API (WordPress 6.9 or newer). Abilities cover product facts, Omnibus price history, GPSR product-safety data, products still missing GPSR data, compliance status and overall store health. Every ability is read-only and protected by a WooCommerce capability check; nothing in your store is changed automatically.
* New: AI product summary - generate a short, plain-language product summary on demand from the product editor. Uses your site's configured AI provider when one is available (WordPress AI Client) and simply does nothing when none is configured.
* New: GPSR safety-text draft helper - generate a draft product-safety text that you review and edit before saving. Drafts only; nothing is published automatically.
* Compatibility: the AI features degrade gracefully when no AI provider is configured, and are forward-compatible with the WordPress AI Client. No third-party AI keys are stored by the plugin.

= 1.20.1 =
* Fixed: the admin screens now load their scripts reliably. The bundled admin and frontend scripts are emitted as classic browser scripts (with their WordPress script dependencies declared) instead of ES modules, so the React-based admin renders correctly across setups.
* Translations: refreshed all bundled locales (Polish, German, Czech, Slovak, Ukrainian, Lithuanian, Belarusian, Simplified Chinese) so every interface string is up to date.

= 1.20.0 =
* New module: Promotions / dynamic pricing (basic). Optional, off by default. Two automatic cart discounts you configure in the module settings: a bulk discount (a percentage off a product line once its quantity reaches a threshold) and a cart discount (a percentage off when the cart subtotal reaches a threshold, applied as a cart fee). Recomputed idempotently from the regular price, safe across WooCommerce's repeated total calculations.

= 1.19.0 =
* New module: Returns and complaints (RMA). Optional, off by default. Customers can open a complaint (reklamacja) or return (zwrot) request for an eligible order from My Account; the request is stored, confirmed by email to the customer and the shop, and managed in a new admin queue (WooCommerce > Polski > Returns & complaints) with status changes (submitted, in progress, resolved, rejected). Mirrors the withdrawal request flow and reuses the consent/order infrastructure. Configurable eligibility window and notification email. Provides tools and templates, not legal advice.
* Storefront module orchestration: unified loader so wishlist, quick-view and other buttons rendered after page load (infinite scroll, AJAX filters, quick-view modal) keep working, with accessibility and performance improvements.

= 1.18.0 =
* Visual identity refresh across the admin: a new Polski brand with self-hosted Schibsted Grotesk and Hanken Grotesk webfonts (font-display swap), a monogram menu icon and a wordmark dashboard header. Admin styling loads only on the plugin's own screens, never on the storefront, to protect Core Web Vitals.
* Storefront structured data: the plugin now augments WooCommerce's own Product and Offer JSON-LD (no duplicate graph) with a priceValidUntil value and, on sale products, the truthful Omnibus lowest 30-day price as a MinimumPrice specification for better rich results and machine readability.
* Expanded localization catalogues for Polish, German, Czech, Slovak, Ukrainian, Simplified Chinese, Belarusian, and Lithuanian, with ongoing translation maintenance.
* Typography cleanup: replaced long dashes with hyphens across interface strings and all translation catalogs for consistent rendering.

= 1.17.0 =
* Store health monitor: new optional module (off by default) for continuous, passive monitoring of store operations. Three sensors run every 5 minutes via WP-Cron: front-end fatal errors (`shutdown` handler, storefront only), the checkout failure rate (observes `woocommerce_checkout_order_processed`, the Store API equivalent, and `woocommerce_order_status_failed` over a rolling 2-hour window), and a sales anomaly check (previous full hour vs the typical order count for the same weekday/hour over the past 8 weeks, evaluated at most once per hour). No synthetic orders are ever placed. Alerts go out by email and optional JSON webhook (Slack/Discord-compatible) with a configurable cooldown; a hard outage also records an entry in the security incident log when that module is enabled. Health dashboard under Reports & Tools with a manual "Run check now", an admin notice when status is not OK, and a read-only REST endpoint `GET /polski/v1/store-health`. Block checkout is covered through the Store API hook. Settings: alert email/webhook, failure-rate threshold and minimum sample, sales anomaly threshold, and alert cooldown.

= 1.15.0 =
* B2B fields: optional "Potrzebuję faktury VAT" toggle, separate from the existing "Buying as a company" checkbox. Polish e-commerce convention treats invoice-need as orthogonal to company-vs-consumer (paragon vs faktura), so the field is its own opt-in. Saves to `_polski_needs_invoice` order meta. Wired through both classic checkout and the WC 8.6+ additional-fields API. New setting `polski_b2b.show_needs_invoice_toggle` (default off).
* Compare: sticky bottom drawer (`polski_compare.show_sticky_bar`, default off) showing thumbnails of compared products with a "Porównaj (N)" CTA and a clear-all button. Hidden on the compare page itself; auto-suppressed when the list is empty. Mobile-responsive CSS.
* Compare: new shortcode `[polski_compare_count]` for the header counter, with `template`, `class`, and `hide_when_empty` attributes. Renders an anchor to the compare page with a `data-polski-compare-count` attribute that the existing AJAX layer can update live.
* AJAX filters: named presets. `[polski_filters preset="b2b"]` shortcode argument loads overrides from the new `polski_filter_presets` option (`[name => array<setting, value>]`); the inner array is merged over the global filter settings before render. Archives can map to a preset via the `polski/filters/archive_preset` filter. Per-preset runtime tweaks via `polski/filters/preset` (preset, name).

= 1.14.1 =
* B2B fields: full IBAN validation. `B2BCheckoutService::isPlausibleIban()` now performs the ISO 13616 mod-97 checksum and a country-code length lookup (PL=28, DE=22, GB=22, FR=27, IT=27, plus 25 more EU/CH/GB markets). Replaces the previous structural-only sanity check.
* DSA: per-IP rate limiting on the report submission handler. Default 5 reports per hour per IP; window and limit are filterable via `polski/dsa/rate_limit_window_seconds` and `polski/dsa/rate_limit_max_attempts`. Source IP is filterable via `polski/dsa/rate_limit_ip` for sites behind a reverse proxy.
* Code quality: tighter Plugin Check compliance in pre-existing modules. CRA `IncidentRepository` now uses `%i` placeholders instead of interpolated `{$table}` queries; `FilterService` documents the read-only GET-based filter context with a scoped `phpcs:disable`/`enable` block instead of leaving a Recommended warning open; `CRAIncidentsPage` adds `wp_unslash()` + `sanitize_key()` before passing `$_POST['kind']` and `$_POST['severity']` to `IncidentKind::tryFrom()` and `Severity::tryFrom()`; `templates/forms/ajax-filters.php` sanitises single-string `$_GET[$key]` reads.

= 1.14.0 =
* B2B checkout fields: Block-checkout support via `woocommerce_register_additional_checkout_field` (WC 8.6+). NIP, REGON, and IBAN now appear in both classic and Block checkouts from a single registration. Values written by the WC additional-fields API are mirrored to legacy `_billing_nip`, `_billing_regon`, `_billing_iban` order meta on save (`woocommerce_set_additional_field_value`) so the existing KSeF and invoice modules pick them up unchanged. The classic-only `woocommerce_billing_fields` path is automatically skipped when the modern API is available, preventing duplicate billing rows. Stores on WC < 8.6 continue to use the classic-only path with the company toggle.
* DSA module: per-product report widget. Optional collapsible "Zgłoś nielegalne treści (DSA)" section on single product pages with the report form prefilled with the product permalink and human-readable name. The form posts to the existing `polski_dsa_report` admin-post handler, so reports flow into the same admin queue as shortcode submissions. Configurable position (after product summary or in product meta block). New filter `polski/dsa/product_widget_enabled`. Defaults `polski_dsa.product_widget_enabled` (off) and `polski_dsa.product_widget_position` (`after_summary`).
* DSA module: defaults populated for `polski_dsa` (`contact_email`, `form_title`, `form_intro`, plus the new widget keys) so admins see seeded values on first activation instead of empty strings.

= 1.13.0 =
* New module: B2B checkout fields. Adds an optional "Buying as a company" toggle plus NIP, REGON, and IBAN fields to WooCommerce classic checkout, with conditional show/hide tied to the toggle. NIP is validated on submit using the official Polish checksum algorithm and saved to standard `_billing_nip` meta so existing KSeF and invoice integrations can pick it up without changes. REGON accepts 9- or 14-digit numbers; IBAN passes a structural sanity check (country prefix + 13-32 alphanumeric body, length 15-34). Settings group `polski_b2b` (`enabled`, `show_company_toggle`, `nip`, `regon`, `iban`). New static utility `Polski\Util\NipValidator` (`isValid`, `normalize`, `format`). If another integration registers a NIP field, Polski skips its own NIP registration to avoid a duplicate field.

= 1.12.0 =
* AI Feed: `/llms.txt` manifest at the site root following the open standard at https://llmstxt.org. AI agents that look for the well-known file at `/llms.txt` now get a Markdown index of the site - title, description, legal pages with `?output_format=md` links, the WooCommerce shop page, and the top product categories. Filters: `polski/ai_feed/llms_txt_enabled`, `polski/ai_feed/llms_txt_sections`, `polski/ai_feed/llms_txt_category_limit`. Setting `polski_ai_feed.llms_txt_enabled` (default `true`).

= 1.11.0 =
* New module: AI Feed. Serves singular posts, pages, and WooCommerce products as Markdown via content negotiation so AI agents and LLM crawlers can ingest store content without scraping HTML. Triggered by `Accept: text/markdown` header or `?output_format=md` query argument. Adds `<link rel="alternate" type="text/markdown">` to single views for discovery and a "View AI Version" row action on the Posts, Pages, and Products list screens.
* AI Feed: product Markdown enriched with Polish-market data - SKU, GTIN/EAN, gross/regular/sale price, currency, tax class, Omnibus lowest price (last 30 days), delivery time, stock quantity and availability, weight, dimensions, brand, manufacturer, GPSR responsible person, and product categories. Front matter exposes the same fields as YAML for structured ingestion.
* AI Feed: filters `polski/ai_feed/enabled`, `polski/ai_feed/post_types`, `polski/ai_feed/post_markdown`, `polski/ai_feed/product_markdown`, `polski/ai_feed/product_facts`, `polski/ai_feed/password_required`. Settings group `polski_ai_feed` (`enabled`, `post_types`). Default post types: `post`, `page`, `product`.

= 1.10.0 =
* New module: OSS observer. Tracks the EU intra-community €10,000 B2C delivery threshold by integrating with the standalone One Stop Shop plugin. One-click install + activation directly from the module row. WooCommerce admin note prompts install when the observer is toggled on without the external plugin present. Exposes the filter `polski_tax_oss_enabled` so custom tax integrations can branch tax logic on OSS state.
* Modules page: redesigned as a WP list-table (Name / Enabled / Description / Edit) with MoSCoW-prioritised grouping - Legal & Compliance, Tax & Pricing, Checkout & Orders, Content & Trust, Advanced & Tools. Pencil icon opens a dedicated settings subpage per bucket (`admin.php?page=polski-group-<bucket>#polski-module-<id>`) registered dynamically for every module with settings, enabled or not.
* Setup wizard: rewritten as a 5-step guided flow (Company > Legal > Tax & OSS > Checkout > Finish). Each step uses toggle rows with inline description panels; optional steps have Skip Step + Continue; OSS toggle on the Tax step triggers One Stop Shop plugin install on Finish.
* Dashboard: "Relaunch setup wizard" button for merchants who want to rerun the guided setup after completion.

= 1.9.1 =
* Compliance checklist: Accessibility (WCAG) section - 9 heuristic rules scanned against the static homepage HTML (html lang, skip link, h1, viewport meta, main landmark, search role, focus outline, autoplay sound, missing img alt). REST: `GET /polski/v1/compliance/accessibility`.
* Compliance checklist: Cookie banner now includes a push-notification prompt detector - flags `Notification.requestPermission`, `PushManager.subscribe` and common third-party push SDKs triggered without user interaction.
* New module: RODO training documentation generator. Admin page `Polski > RODO training docs` downloads three printable HTML templates (training logbook, principles summary, data-breach response playbook). Pre-branded with shop data from the setup wizard.

= 1.9.0 =
* New module: Complaint template generator. Ready-to-print complaint form (formularz reklamacyjny) auto-populated with seller data. Admin page `Polski > Complaint template` with preview + download as standalone HTML. `[polski_complaint_template]` shortcode to embed on customer pages.
* New module: Copyright / license notice helpers. `[polski_copyright]` shortcode + `polski/copyright` block with year, owner and optional license. `[polski_image_credit]` shortcode for per-image credits with source link and license.

= 1.8.2 =
* New module: Business identification. Renders the shop's business data (name, address, NIP, REGON, email, phone) as a `[polski_business_info]` shortcode and a dynamic Gutenberg block `polski/business-info`. Reads values set in the setup wizard (`polski_general` option). Block and inline formats with configurable separator.

= 1.8.1 =
* New module: SBOM generator. Emits a CycloneDX 1.4 JSON document listing PHP (composer.lock) and JS (package-lock.json) dependencies plus plugin metadata. Admin page `Polski > SBOM` with one-click download. Content-Type `application/vnd.cyclonedx+json` - ready for Dependency-Track / Trivy.

= 1.8.0 =
* New module: CRA incident reporting. Records actively-exploited vulnerabilities and security incidents with a CRA Article 14 early-warning deadline (24h for incidents/exploits, 72h for near misses). Admin page `Polski > CRA incidents` to record, dispatch (webhook + email) and mark resolved. JSON export per ENISA SRP draft schema. Hourly cron checks for deadlines approaching. Action hooks `polski_cra_incident_recorded` and `polski_cra_incident_deadline_approaching`. Migration 2.1.0 creates `polski_cra_incidents`.

= 1.7.2 =
* Site audit: four new dark-pattern checks. Forced account creation (EU Directive 2023/2673), stale/fake sale countdowns (products still on-sale after date_to passed), misleading "from" price on variable products with >50% min/max spread, false urgency via oversized low-stock threshold (>5).

= 1.7.1 =
* Compliance checklist: added Cookie banner (active consent) section. Scans the homepage HTML with a 1h transient cache and reports 9 rules (banner presence, Accept, Reject with equal prominence, granular settings, Analytics/Marketing categories, privacy-policy link, withdrawal hint, implied-consent phrase trap).
* REST API: `GET /polski/v1/compliance/cookie-banner?url=` returns the cookie-banner checklist as JSON.
* 5 new unit tests.

= 1.7.0 =
* New module: Compliance checklist for Privacy Policy (RODO Art. 13) and Regulamin (Ustawa o swiadczeniu uslug / Ustawa o prawach konsumenta). Structural heuristic scanner with 17 + 15 rules, severity levels (Required/Recommended/Optional), and a WP-admin checklist page showing score and per-element pass/fail.
* REST API: `GET /polski/v1/compliance/page/{privacy|terms}` returns the full checklist as JSON.
* Admin: new submenu Polski > Compliance checklist.
* 12 unit tests covering normalization (HTML + diacritic strip), rule evaluation, score math and default rule sets.

= 1.6.3 =
* Fixed: Added per-line `phpcs:ignore` annotations with justifications on all `$wpdb` custom-table calls (repositories, Migrator, DSAService, uninstall.php)
* Fixed: Added `phpcs:ignore` annotations on `meta_key` / `meta_value` / `meta_query` / `tax_query` lookups in service classes (ExpertReview, DoubleOptIn, SocialLogin, ReviewRequest, Faq)
* Fixed: Added `phpcs:ignore` on WooCommerce email header/footer `do_action()` invocations in email templates
* Result: Plugin Check now reports 0 errors and 0 warnings on the built release package

= 1.6.2 =
* Fixed: Softened plugin description and FAQ wording to avoid implying legal compliance or legal guarantees
* Fixed: Documented Google OAuth, Facebook OAuth, and Google Tag Manager / Google Analytics in External Services
* Fixed: Removed broken GitHub support links from the admin sidebar and deactivation modal
* Fixed: Hardened remaining `$_GET` and `$_POST` handling in admin and storefront flows
* Fixed: Replaced internal `wp_redirect()` calls with `wp_safe_redirect()` where the target stays on-site
* Fixed: Removed HEREDOC usage from review request emails for better Plugin Check compatibility
* Fixed: Replaced all remaining inline `<script>` tags (DataLayer events, JSON-LD schema) with `wp_print_inline_script_tag()` / `wp_print_script_tag()`
* Fixed: Refactored repository queries to use `$wpdb->prepare()` with `%i` table-name placeholder (eliminates table-name interpolation suppressions)
* Fixed: Replaced raw `echo $html` in Elementor widgets with `wp_kses_post()`
* Fixed: Prefixed all template variables with `polski_` to satisfy WordPress.org naming conventions
* Fixed: Removed dozens of phpcs:ignore suppressions in favour of real fixes

= 1.6.1 =
* Fixed: Moved inline admin CSS and JS to enqueued asset files (wp_enqueue_style / wp_enqueue_script)
* Fixed: Sanitized $_GET inputs in the AJAX product filters template
* Fixed: Removed manual load_plugin_textdomain() call (WordPress.org auto-loads translations since WP 4.6)
* Fixed: Hardened nonce verification by sanitizing $_POST values before passing to wp_verify_nonce()
* Fixed: Added missing wp_unslash() and capability check in expert review and product meta save flows
* Fixed: Updated readme.txt Contributors username and removed broken donate / GitHub repository links

= 1.6.0 =
* Added Social Login module (Google + Facebook OAuth2 with auto-registration)
* Added Product Authors taxonomy for bookstores and publishers
* Added Expert Reviews custom post type with ratings and Schema.org markup
* Added Order Export module (CSV with 30+ configurable fields)
* Added FAQ module with categories, accordion shortcode, and Schema.org FAQPage
* Enhanced Custom Checkout Fields with 5 conditional logic types (field value, shipping, payment, category, cart total)

= 1.5.0 =
* Added Auto Restore Stock module - automatically restores product stock on order cancellation, refund or failure
* Added AJAX Add to Cart module - add products to cart without page reload, including variable products
* Added Custom Checkout Fields module - add, modify and reorder checkout fields with multiple field types and validation
* New "Stock & Cart" and "Checkout" module groups in the admin panel

= 1.4.0 =
* Added "From price" display for variable products (shows "from XX PLN" instead of price range)
* Added minimum order value and quantity rules with cart validation
* Added automated review request emails after order completion
* Added opt-out support for review request emails
* Improved localization: all __() fallback strings now use English source language

= 1.3.0 =
* Added GPSR module: 8 product fields, CSV bulk import/export, status column in product list, product page display
* Added customer withdrawal request flow in My Account (EU Directive 2023/2673)
* Added DSA Toolkit: report form shortcode, admin reports page, email notifications
* Added KSeF-ready module: NIP-based auto-detection, integration hooks, order list column
* Added Security incidents module: CRA-oriented incident log with status tracking and CSV export
* Added verified purchase badge for product reviews
* Expanded Site Audit with DPA, DSA, KSeF-ready, anti-greenwashing, verified review, and security incident checks
* Added anti-greenwashing product fields (eco claim basis, certificate, expiry)
* Added dynamic per-module settings pages in WordPress admin menu
* Fixed GPSR rendering on WooCommerce Blocks single product pages
* Streamlined free version for WordPress.org submission
* 5 language packs: Polish, German, Czech, Slovak, Ukrainian

= 1.1.0 =
* Added storefront modules (compare, quick view, badges, tabs, video, zoom, slider, infinite scroll, popups)
* Added configurable admin and email copy
* Added customer flows for withdrawal and waitlist
* Improved WooCommerce Blocks checkout support

= 1.0.0 =
* Initial release
* GDPR checkboxes, Omnibus Directive, withdrawal forms
* Shopmarks: unit prices, delivery times, tax notices
* Wishlist, waitlist features
* Food product information fields
* REST API, WP-CLI, CSV import/export
* Full Polish translation

== Disclaimer ==

THIS PLUGIN IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

WPPoland (wppoland.com) shall not be liable for any direct, indirect, incidental, special, consequential or exemplary damages, including but not limited to damages for loss of profits, goodwill, data, or other intangible losses, resulting from the use or inability to use this plugin.

This plugin provides technical tools and templates for WooCommerce stores. It does not constitute legal advice and does not guarantee compliance. Review all generated texts and settings before using them in production. Always test in a development or staging environment before deploying to a live store.

WPPoland bears no responsibility for any legal, financial, regulatory, or other consequences arising from the use of this plugin. By installing and activating this plugin, you acknowledge that you do so entirely at your own risk.
