Start by treating every customer photo as a piece of user content you don’t yet have the right to publish. The simplest safe route that works for most shops: capture explicit consent at upload, keep submissions in a private moderation queue (run automated pre-filters but require a human to approve), and store a provenance record that travels with the image.
Contents
Consent capture: add a checkbox and store the record
When a customer uploads a photo (review form, account area or a dedicated UGC uploader), present a short, clear consent checkbox and do not publish the image until approval. Store the consent value plus a timestamp and the association (order number, user ID or account handle) together with the saved media item so you can later show or audit why you published that image.
Technically, implement this by saving the file as a media attachment and recording consent data in the attachment’s metadata or postmeta. WordPress provides server-side helpers and REST endpoints for creating and querying media items you can use for this workflow; see the media_handle_upload helper and the REST API Media endpoint for programmatic creation and metadata storage.
Practical note: do not treat the checkbox text below as legal advice. For jurisdiction‑specific wording and assignment clauses consult legal counsel before relying on them.
Sample checkbox text (copy/paste):
I grant [Shop name] permission to publish this photo on product pages and marketing materials. I confirm I have the right to grant this permission.
Moderation pipeline: staging queue, automated pre-filters, human final review
Don’t attach or publish uploaded files directly to product pages. Instead:
- Save submissions to a private or pending media state (an attachment with a moderation flag) so they are not publicly accessible until approved.
- Run automated pre-filters to flag obvious problems: adult or violent content, personal documents, or low-quality/irrelevant images. Automation speeds triage, but must not be the final decision-maker.
- Require a human reviewer to examine flagged images and decide approve/reject. Record that decision and the reviewer identity and timestamp.
For automated checks you can use image moderation services that return category flags and scores; these are intended as a pre-filter and to surface likely violations to human moderators. See OpenAI’s moderation guidance for how an automated moderation model reports image/text flags and why a human‑in‑the‑loop is required: OpenAI moderation guide.
A compact workflow (what happens in the system)
- Customer uploads file and ticks consent box; uploader records uploader handle, order/user ID and consent timestamp.
- Server saves the file as a private/pending media item (not attached to a product) and stores the consent metadata on the attachment.
- Automated moderation runs and sets flags on the media record (possible face, document, adult content, low relevance).
- A moderator reviews the queue, examines flags and either approves (publishes/attaches to product) or rejects (delete/archive with a rejection reason logged).
- If approved, the publishing step writes the reviewer decision, approval timestamp and any applied edits into the provenance record and makes the image public.
Provenance and metadata: what to record and how to expose it
Every published customer image should have a provenance record you can audit. Useful fields include:
- uploader name or handle (as supplied by the uploader)
- upload date/time
- associated order ID or account ID
- consent value and consent timestamp
- automated moderation flags and scores (if any)
- moderator ID, decision (approve/reject), and decision timestamp
- edits applied before publishing (crop, resize, watermark) and by whom
- whether commercial publication rights were confirmed
Store these as attachment meta or in a linked provenance table (a custom post type or separate database table), and keep the record immutable once published (append-only audit entries are useful). When you need to expose provenance on a product page, publish a small visible credit (for example, “Photo by Anna, submitted 2026-07-10”) and keep the full provenance entry in the admin for audits.
If you embed provenance as machine-readable data, use schema.org’s ImageObject properties such as author, contentUrl and datePublished. See schema.org/ImageObject for the available fields and their intended meaning.
{
"@context": "https://schema.org",
"@type": "ImageObject",
"contentUrl": "https://example.com/wp-content/uploads/2026/07/customer-photo.jpg",
"author": "Anna",
"datePublished": "2026-07-10T13:42:00+00:00",
"creditText": "Photo submitted by customer"
}
Do not embed private consent tokens or personally identifying storage paths in public JSON-LD. Keep consent evidence in your private admin records, and publish only the non-sensitive provenance shown above.
Practical tests you can run (a short checklist)
- Implement the upload form: include file input, uploader handle field (or use logged-in user), explicit consent checkbox and a hidden field for order ID when applicable.
- Submit a normal image and a deliberately disallowed test image (for example, a screenshot of a document or an intentionally flagged pattern) and confirm both are saved to the pending/private media state, not publicly visible.
- Verify automated pre-filter flags appear on the media record for the disallowed test image and not for the normal image.
- Use the moderator interface to approve one image and reject the other; ensure the reviewer decision, timestamp and reason are recorded.
- After approval, confirm the image is attached to the intended product page, the public credit is displayed as planned, and the provenance metadata (uploader, upload date, consent record) is present in the admin media metadata or your provenance store.
- Spot-check theme cropping and gallery behaviour after publishing. WooCommerce’s image guidance is useful when testing gallery and thumbnail behaviour: WooCommerce image and gallery guidance.
Observable check: when you approve a test image, open the published product page in an incognito browser and confirm the image and the visible credit appear; then open the media item in the WordPress admin and confirm the recorded provenance entries exist and are timestamped.
Platform and host checks you must run in your own account
- Check PHP and host upload limits (upload_max_filesize, post_max_size) and adjust client-side file-size validation accordingly; see WordPress guidance on PHP limits: PHP configuration and limits.
- Decide whether uploads are stored on your origin or an object store/CDN. If you plan private staging, ensure files saved as private remain inaccessible until approval (your storage and CDN must respect privacy settings).
- Review your host’s retention and backup policy for user uploads and plan how long you keep rejected files and consent logs.
Important limits: do not assume a global file-size limit — hosts and PHP settings vary. Run an upload test for typical smartphone photos used by your customers and confirm they pass your configured limits.
Worked example (staging WooCommerce/WordPress): The following is a compact, copyable walkthrough you can run in a staging copy to replicate the end-to-end flow and check results.
- Create an upload form on a staging product review page (or use a custom uploader plugin). Include: file input, uploader name field (or use logged-in user), an order ID field (hidden when not available) and the consent checkbox using the sample text above.
- On submission, save the uploaded file as a private media attachment and add these attachment postmeta keys (example values shown):
consent=true consent_timestamp=2026-07-10T13:42:00Z uploader_handle=anna order_id=12345 moderation_state=pending - Run your automated pre-filter and record flags on the attachment meta, for example:
moderation_flags={"face_closeup":0.92,"document":0.00,"adult":0.02} moderation_summary="face_closeup"These are example keys and numeric scores your moderation service might return; keep them for the audit trail but do not use them as the sole publish decision.
- In the admin moderator interface inspect the pending item and then approve it. Record the approval meta, for example:
moderator_id=7 decision=approve decision_timestamp=2026-07-10T14:05:00Z published_by=moderator - On approval, attach the media to the product and publish a visible credit such as “Photo by Anna — submitted 2026-07-10”. Verify the result:
- Open the product page in an incognito browser — confirm the image and the visible credit appear.
- Open the media item in the WordPress admin — confirm the postmeta keys shown above (consent, consent_timestamp, uploader_handle, moderation_flags, moderator_id, decision_timestamp) are present with the expected values.
This is a hypothetical but actionable example you can run in staging; adjust timestamps, IDs and field names to match your plugin or theme. The exact meta keys shown are examples — your implementation should store the same evidence: consent, uploader association, moderation flags and reviewer decision so audits are possible.
Finish and related guides
Start by implementing the minimal safe flow: (1) uploader with explicit consent checkbox, (2) save uploads privately with consent metadata, (3) run automated pre-filters, and (4) require a human moderator to approve before publishing. Run the practical tests above in a staging copy of your shop until the moderation workflow reliably keeps rejected items private and records complete provenance for every published image.
Useful additional reading from our guides:
- Responsible AI image use: licensing and commercial-use checklist
- Optimize product image filenames, captions and image sitemaps
Remember: automation helps triage but doesn’t replace a human decision. Record everything you rely on (consent, reviewer decision, edits) and keep the provenance data accessible for audits.

