=== CrocoAI Data Bridge ===
Contributors: ristorehemagi
Tags: woocommerce, product sync, catalog, api
Requires at least: 6.6
Tested up to: 7.1
Requires PHP: 8.1
WC requires at least: 9.9
Stable tag: 1.0.8
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

A secure API bridge for reading and publishing WooCommerce catalog data.

== Description ==

Croco provides an authenticated REST API for reading a WooCommerce catalog and applying reviewed,
prepared product releases. It can be used by any compatible API client; a Croco subscription or
Croco service account is not required.

The WordPress admin contains Jobs and Health screens. Health creates or rotates one site-wide API
key and shows the full key only once. Bridge requests use the `X-Croco-API-Key` header. WordPress
Application Passwords are not bridge credentials. Authenticated clients can inspect supported
operations, limits, and quick-edit constraints through `GET /wp-json/crocoai-data-bridge/v1/capabilities`.

Croco can read products, variations, categories, attributes, prices, inventory, dimensions, media
URLs, and Croco-managed metadata. Authorized clients can publish product and media changes. Treat
the API key like an administrator credential and use the bridge only over HTTPS.

[Croco](https://crocoai.com/) is an optional compatible catalog-management service. The plugin is
fully usable without purchasing or registering for that service.

== Installation ==

1. Install and activate WooCommerce.
2. Install and activate CrocoAI Data Bridge.
3. Open WooCommerce > CrocoAI.
4. Open Health, create the API key, and copy it into your API client's protected environment.
5. Call the authenticated capabilities endpoint before using catalog or publication operations.

== Privacy ==

Croco does not contain analytics, advertising, telemetry, or automatic communication with the Croco
service. Catalog data leaves WordPress only when an administrator gives the generated API key to a
client and that client requests it. The plugin may download product images from URLs explicitly
included in an authenticated publication request.

WordPress stores only a password hash, fingerprint, and timestamps for the active API key. The
plain-text key is shown once when it is created or rotated. Publication history, catalog identity
links, job records, and prepared-media records are stored in the WordPress database.

By default, this operational data remains after uninstall so an accidental removal can be reversed.
Administrators can enable permanent data removal from WooCommerce > CrocoAI > Health before
uninstalling. Product posts, terms, and media already published to WooCommerce are not removed.

== Frequently Asked Questions ==

= Do I need a Croco subscription? =

No. The plugin exposes a documented authenticated bridge that can be used by any compatible API
client. The Croco service is one optional client.

= What can an API key do? =

It can read catalog and diagnostic data and invoke the bridge's product, taxonomy, media, and staged
publication operations. It cannot create or rotate API keys. Store the key securely and use HTTPS.

= Does the plugin send telemetry or contact Croco automatically? =

No. It does not send analytics or telemetry and does not connect to the Croco service by itself.

= What happens when I uninstall the plugin? =

Operational tables and settings are retained by default. Enable permanent data removal in Health
before uninstalling to delete those tables and settings. Published WooCommerce content remains.

= Where is the readable admin JavaScript? =

`assets/build/admin.js` is a generated bundle. The readable, non-minified source is
`assets/src/admin.js`, with styles in `assets/src/admin.css`. Both source files are included in
the plugin zip.

== Changelog ==

= 1.0.8 =
* Include native WooCommerce product brands in catalog product records as `brands` entries with term ID, name, and slug.

= 1.0.7 =
* Prepare all direct SQL values and table identifiers, including dynamic ID lists and allowlisted update columns.
* Document the Electro-owned specifications meta key without exposing it as a plugin-owned global identifier.
* Prefix uninstall-scope variables and prepare the fixed table identifiers used during data removal.

= 1.0.6 =
* Walk category paths in their own language. Under WPML, a translated product walked English names while Estonian was current, could not see the English terms, and made a new root category copy on each attempt.
* A translation no longer creates original-language categories. A missing original category now stops the item with an error.

= 1.0.5 =
* Map uploaded meta_title and meta_description to Yoast SEO and Rank Math metadata, with translated content and merchant ownership support.
* Detect SEO-only and custom-metadata-only updates, preserve omitted fields, and support clearing and idempotent retries.

= 1.0.4 =
* Use WordPress automatic translation loading and remove the unused languages directory header to resolve Plugin Check translation findings.

= 1.0.3 =
* Package the renamed CrocoAI Data Bridge with the crocoai-data-bridge plugin slug and current main branch changes.

= 1.0.2 =
* Rename the plugin to CrocoAI Data Bridge and the WordPress.org slug/text domain to `crocoai-data-bridge`. Existing option keys, tables, post meta, and Action Scheduler events are migrated on activation or upgrade. The previous `wpi/v1` REST namespace remains as a compatibility alias.
* Keep WPML from copying the Croco translation identity of the original product into its duplicates. A re-published product failed with "A product is already linked to a different Croco identity" for each duplicate language.
* Repair a duplicate that already carries the identity of the same product in another language, instead of refusing it.

= 1.0.0 =
* Prepare the plugin for its public `crocoai-data-bridge` slug, author metadata, translations, and WooCommerce dependency declaration.
* Document standalone bridge use, authentication scope, privacy behavior, and uninstall retention.
* Add an administrator control for deleting Croco operational data during uninstall.
* Extend product quick edits to name, short and full descriptions, and ordered existing image attachments.
* Support dynamic product attribute quick edits using existing global term IDs or product-specific string values.

= 0.10.7 =
* Let product publication run while Croco prepares and uploads images.
* Hold media processing behind a bounded gate, and open it when Croco signals readiness.
* Open the gate after its timeout so the existing source-URL fallback cannot remain blocked.

= 0.10.6 =
* Add prepared staged assets v2 so Croco can generate the exact WordPress image renditions before upload.
* Validate image-profile freshness, checksums, MIME types, dimensions, and complete rendition sets before registering media.
* Preserve the v1 staged-asset fallback and reuse verified v2 attachments without re-uploading or resizing.

= 0.10.5 =
* Add authenticated capability discovery with machine-readable routes, quick-edit fields, constraints, and semantics.
* Publish WordPress REST argument and response schemas for the quick-edit endpoint.
* Return an empty JSON object for the no-op changed_fields map.

= 0.10.4 =
* Publish the completed 0.10.3 candidate under a correctly incremented release version.

= 0.10.3 =
* Hash unusually long source image filenames before sideloading them so attachment GUIDs fit WordPress database limits.
* Convert every linked multilingual variation in place during `variation_to_simple`, preserve translated child IDs, and roll back the complete language family.
* Move each former variable parent to Trash only after its final variation has been detached.

= 0.10.2 =

* Link unambiguous source and translated attribute terms during provisioning without reassigning pre-existing merchant translation groups.
* Preserve existing WooCommerce attribute labels when Croco sends only the attribute key; require a display name only when creating a new attribute.

= 0.10.1 =

* Rename attribute-value display names without resubmitting shared WPML term slugs.

= 0.10.0 =

* Add one API-key-authenticated PATCH endpoint for immediate allowlisted product status, category, price, and stock edits.
* Validate the complete requested product state before one WooCommerce save and return persisted values with exact before/after changes.
* Keep quick edits temporary: staged Croco releases remain authoritative and may overwrite source-managed fields.
* Add an exact attribute-value display-name operation that preserves term slugs, identities, and product relationships.

= 0.9.3 =

* Preflight WPML category and attribute-option translations before changing a product.
* Reuse correct existing option translations and report hierarchy mismatches separately from translation-group conflicts without reassigning merchant terms.
* Recover partially written products by Croco translation identity, preserve their WooCommerce IDs in failure results, and make retries idempotent.

= 0.9.2 =

* Preserve the validated variation destination ID through update publication so protocol 5 compares the intended WooCommerce IDs.
* Normalize variation-to-simple IDs as positive integers and reject missing, malformed, Boolean, compound, zero, and negative values before mutation.
* Revalidate the exact source variation, destination identity, and variable parent immediately before conversion while retaining idempotent retries.

= 0.9.1 =

* Move one exact product-attribute term use between two existing global-attribute taxonomies without creating schema or translation records.
* Preserve existing target values and settings, remove empty source definitions, report active and stale scope separately, and make retries no-ops.
* Detect staged attribute-key replacements even when product categories are merchant-owned.

= 0.9.0 =

* Report and accept selected-release protocol 5 while retaining protocols 2, 3, and 4.
* Convert one confirmed variation record into a top-level simple product without changing its ID, SKU, Croco identity, former parent, or siblings.
* Validate the exact variation, parent, SKU, and identity before mutation; make successful retries idempotent and refresh WooCommerce derived data.

= 0.8.5 =

* Requeue source-owned product images when the saved URLs match but the completed attachments are missing, incomplete, or in a different order.
* Keep unchanged image sets out of the media queue only when every cached attachment is still attached to the target product in the requested order.

= 0.8.4 =

* Cancel queued, active, media-processing, or paused uploads without reverting changes already applied to WooCommerce.
* Unschedule remaining product and media work, release the job worker lock, and prevent cancelled uploads from resuming.
* Complete fully processed product jobs before taxonomy maintenance, and requeue media that a cancelled or failed job did not attach.

= 0.8.2 =

* Reassign one exact global-attribute term to another by term ID or slug without ambiguous name lookup.
* Report term language and translation identities, preserve unrelated attributes, update variation axes, clean stale relationships, and refresh affected lookup rows.
* Keep the source term by default so an operator can verify the changed product IDs before deletion.

= 0.8.1 =

* Prevent WooCommerce Multilingual attribute lookup synchronization from calling `set_options()` on a missing duplicate attribute during structural updates.

= 0.8.0 =

* Report and accept selected-release protocol 4 while retaining frozen protocol 2 and protocol 3 releases.
* Report the detected multilingual plugin as wpml, polylang, or none in bridge diagnostics.
* Merge primary and translated product attributes by stable key and preserve each merchant-owned attribute.
* Apply the same ownership merge to variation axes, translated terms, and staged change detection.
* Reject malformed attribute ownership and ownership content sent with a protocol lower than 4.

= 0.7.2 =

* Resolve duplicate-mode attributes through existing translated term identities.
* Keep the source term when no translation exists instead of creating a target-language copy.
* Apply translated option slugs and shared values to duplicate variations on updates.

= 0.7.1 =

* Initialise Electro's attribute specification display on Croco product saves.
* Keep WPML product and term identities independent of the request language.
* Preserve translated content after source saves and synchronise shared commercial values.
* Export and display product attributes in the product language.
* Reuse attribute terms and translation links, and remove redundant publication saves.
* Reject incomplete WPML dependencies and preserve original publication errors.

= 0.7.0 =

* Support protocol 3 translated Clean product and variation overrides for WPML and Polylang while preserving protocol 2 duplicate releases.
* Provision translated category identities, attribute labels, and localized option terms before staged items are published.
* Keep translated parents and variations retry-safe through stable Croco client, external product, and language identities.
* Return translation maps in staged item results and capture localized translation links, text, categories, attributes, and variation data.
* Reject inactive multilingual plugins, unknown languages, unresolved translated identities, incomplete variable families, conflicting links, and translated overrides sent under an older release protocol.

= 0.6.0 =

* Require selected-release protocol 2 and a complete product-family manifest.
* Validate family axes, option combinations, parent value unions, and manifest scope before publication.
* Keep parent-before-variation processing and report results by product family.
* Support soft variation retirement, stable simple-variant links, and confirmed in-place structural migration with family rollback.
* Publish variant cost through WooCommerce Cost of Goods Sold. WooCommerce 9.9 or newer and the Cost of Goods Sold feature are required when a release contains cost.

= 0.5.1 =
* Update every requested existing product duplicate during confirmed publication. Duplicate mode now keeps Croco-managed title, description, price, inventory, dimensions, categories, attributes, and managed metadata current in each language instead of only checking that the translated post exists.
* Keep translation synchronization out of release preparation. No translated product value changes before the publication job runs.

= 0.5.0 =
* Identify a product attribute by its slug, not by its label. Croco sends each attribute as `{key, name, values}`; the key is the slug the store keeps the taxonomy under and the name is the label shown over it. A renamed attribute now updates its label in place instead of becoming a second attribute beside the first.
* Refuse an attribute key of 28 characters or more with a message that names the attribute. WooCommerce refused the slug and reported only the slug, so a long attribute name failed an upload with nothing to act on.
* Report each product attribute with its key in the catalog read, so a reader compares identities and not labels.
* Report bridge protocol 3 in diagnostics. A label-keyed attribute payload is still accepted, so Croco and this plugin can be deployed in either order.

= 0.4.1 =
* Keep the admin screen alive when the open tab changes. `useData` passed its loader straight to `useEffect`, and that loader returns a promise. React treats an effect's return value as the cleanup function, so leaving Jobs made React call a promise, which threw `TypeError` and unmounted the whole screen. The page went blank and Health — the only place that creates the API key — could not be reached.

= 0.4.0 =
* Replace WordPress Application Password bridge authentication with one rotatable Croco API key.
* Reduce the administrator interface to Jobs and Health, including one-time key creation and rotation.
* Remove legacy source, mapping, normalization, run, review, alias, and settings REST routes.
* Retire legacy source scheduling while preserving staged-release data, links, and historical tables.
* Report bridge protocol 2 in diagnostics.

= 0.3.33 =
* Export each translated product with category IDs from that product's language. A multilingual catalog request could previously return the default-language term IDs for translated product versions.

= 0.3.32 =
* Duplicate a product with a call WPML answers. `wpml_make_duplicate` is not a hook WPML registers, so `do_action` on it created nothing and said nothing, and every translated publication failed on a store that was working correctly. Each way of duplicating is now tried in turn, most exact first, and the result is checked after each. The error names what was tried.
* Report the plugin's real version. `CROCOAI_DBRIDGE_VERSION` was last set at 0.3.28, so 0.3.29, 0.3.30 and 0.3.31 all reported themselves as 0.3.28 in diagnostics and in every version check that reads it. Packaging now refuses to build when the plugin header, the constant and the stable tag disagree.

= 0.3.31 =
* Discard a product whose translation failed. A create that reached WooCommerce and then failed to make its translation left the product on the store as a draft: nothing pointed at it, it held the SKU a retry needs, and it had no images, because media import happens after that point and was never reached. The product and any translation of it made by the same call are now removed, so the item fails as a whole.
* Report which duplication hooks WPML listens for. `crocoai-data-bridge/v1/diagnostics` now says whether `wpml_make_duplicate` and `wpml_admin_make_post_duplicates` have a listener on this store. A `do_action` on a hook nobody registered creates nothing and reports nothing, which reads exactly like a duplication that ran and failed.

= 0.3.30 =
* Give a translated copy the images of its original. A translation is duplicated when the product is published, which is before its images are imported, so the copy was made from a product that had none.

= 0.3.29 =
* Detect WPML by WPML itself. Polylang registers the WPML compatibility filters, so the store reported WPML and the wrong adapter refused to publish a Polylang translation.
* Duplicate a product into a Polylang language without the paid WooCommerce add-on. The post, its meta, its terms and its variations are copied, and the copy is linked as the translation.
* Give a duplicate only the categories that exist in its own language. An untranslated term is left for the publisher to set.

= 0.3.28 =
* Drop a source link whose WooCommerce product no longer exists, and report a store id only when it still resolves to a product.

= 0.3.27 =
* Resolve the image URLs of one catalog page from a primed cache. A lookup for each image made the capture too slow.

= 0.3.26 =
* Send image URLs with the catalog payload so Croco can capture merchant-owned images, not only their identifiers.

= 0.3.25 =
* Update the storefront-language product, not the WPML source original, when those are different.
* After publication, set each language copy to its own category term. Do not put the English category name on the Estonian product.
* Resolve WPML product translations from the translation map, not only wpml_object_id.

= 0.3.24 =
* Assign product categories by destination term ID. After a WPML duplicate, set the translated term, not the English name.
* Include category language and translation term IDs in the catalog dump.

= 0.3.23 =
* Resolve product categories by name and walked parent. Do not reuse a same-name term at the root.
* Look up product categories in every language so WPML does not hide the nested English term.

= 0.3.22 =
* Resolve SKU updates to the WPML original product, not the store default-language duplicate.
* Return every product category language in the catalog dump used for publication checks.
* Redact import errors without crashing the publication worker.

= 0.3.21 =
* Duplicate published products into the storefront languages that the client configures.
* Link WPML or Polylang translation posts and keep the SKU on the original-language product.

= 0.3.19 =
* Continue serial media batches immediately and record scheduler, download, attachment, and resize timings.

= 0.3.18 =
* Add WPML and WooCommerce Multilingual product-language and category-translation support.

= 0.3.17 =
* Publish and reconcile explicit product backorder policies.

= 0.3.16 =
* Update existing product stock fields and keep WooCommerce product caches current after publication.

= 0.3.15 =
* Add prepared staged releases that queue only after a final publish confirmation.
* Add exact staged item results with WooCommerce IDs and redacted errors.
* Record verified external links for unchanged variable-parent dependencies.
* Report active jobs and all required plugin tables in diagnostics.

= 0.3.0 =
* Add a separate SQLite staging application for immutable snapshots, transformations, review, optimized assets, and releases.
* Add authenticated, idempotent staged-release REST endpoints.
* Accept pre-uploaded WordPress attachment IDs so staged releases avoid remote image downloads and repeated product saves.
* Batch the legacy media worker, deduplicate images through an indexed hash table, and prevent in-flight workers from overriding pause.

= 0.2.2 =
* Serialize database migrations with an expiring atomic lock to prevent upgrade stampedes.

= 0.2.1 =
* Replace full canonical-JSON queue scans with an indexed publication priority.
* Add pause and resume controls for publication jobs.
* Add configurable breathing room between workers and defer bulk cache invalidation.

= 0.2.0 =
* Queue publication instead of running product writes inside REST requests.
* Publish products in restartable, time-budgeted batches with a global worker lock.
* Move images to a single-worker media queue with hard time, size, and retry limits.
* Add publication job progress and bulk run approval controls.
* Stream remote feeds with download-time byte limits and disable synchronous REST imports.

= 0.1.1 =
* Accept XML uploads detected as either text/xml or application/xml.
* Add editable CSV delimiter and XML record-element settings to the source UI.
* Add a direct Configure link on the WordPress Plugins screen.
