Return Manager Documentation
Installation steps and a complete reference for every field and function in the admin, with concrete examples — the same level of detail our support uses to help customers.
Installation
Requirements
Magento 2.4.x — tested on 2.4.9, compatible with previous 2.4.* releases. PHP 8.1–8.5. Compatible with both the default Luma theme and the Hyvä theme. Requires the native Magento_ReCaptcha* modules to be present for the optional reCAPTCHA protection (already bundled with Magento core).
Setup steps
- 1. Add the credentials you'll receive by email to
auth.jsonin your Magento project root:{ "http-basic": { "repo.codingrow.com": { "username": "...", "password": "..." } } } - 2.
composer config repositories.codingrow composer https://repo.codingrow.com - 3.
composer require codingrow/module-return-manager - 4.
bin/magento module:enable Codingrow_ReturnManager - 5.
bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush - 6. Paste your license key into Admin → Stores → Configuration → Codingrow Extensions → Return Manager → License → License Key, save, then
bin/magento cache:flush. - 7. Place the request link somewhere customers will find it — see Placing the widget below.
The whole frontend form, emails and admin interface are available in 7 languages, auto-selected per store/admin locale:
Uninstallation
composer remove codingrow/module-return-manager then
bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:flush.
Requests already recorded in codingrow_returnmanager_request are never
deleted automatically — export the grid first if you need to keep a record.
User guide
The withdrawal request page
One page, two steps, exactly as required by the underlying directive: the customer first fills in the fixed fields (name, email, order number, receipt date) plus any enabled custom fields, sees a read-only summary of everything entered, and only then confirms on a final, separate button. The hidden fields carrying the data forward between the two steps are re-validated server-side on confirmation — a customer can never bypass the checks by forcing the "confirmed" step directly.
Order verification
Before accepting a request, the module checks that the order number actually exists and that the email address matches the one on that order (case-insensitive, works for both guest and registered-customer orders). If either check fails, the same generic "not found" message is shown either way — this is deliberate: revealing "wrong email" versus "order doesn't exist" would let someone probe for valid order numbers by trial and error.
Duplicate-request prevention
One order can have only one active withdrawal request, regardless of its status — even a "Rejected" one. A customer who disagrees with a rejection can't simply resubmit the same request to route around it; if a genuine exception is needed, the admin deletes the previous request from the grid first.
Receipt date & elapsed days
The 14-day withdrawal period starts from when the goods were received, not from the purchase or invoice date — information Magento has no way of knowing on its own, since it depends on the carrier. The form asks for it with a native HTML5 date picker (no jQuery UI dependency that could conflict with a theme), capped so a future date can't be entered. The order date itself is read automatically from the linked order — the customer never has to type it. Both dates, plus the days elapsed since receipt, are shown in the admin grid (flagged once past 14 days) and available as email variables.
Custom fields builder
Beyond the four fields required by law (name, email, order number, receipt date — always mandatory, never removable), you can add an unlimited number of your own fields from Codingrow Extensions → Return Manager → Form Fields: label, type, whether it's required, whether it's currently shown on the form, and its display order relative to the other fields.
| Type | Rendered as |
|---|---|
| Text | Single-line input |
| Textarea | Multi-line box |
| Dropdown | A <select> with the options you typed, one per line |
| Checkbox | A single checkbox (e.g. "I still have the original packaging") |
Values submitted for a field that gets disabled later are kept in the request's history and still shown wherever they were recorded — only the field's label is re-resolved by ID, so renaming a field afterward updates the label everywhere its old answers are displayed too.
"Items to return" field
A dedicated optional field (disabled by default, since it isn't part of the legal minimum) for a free-text description of what's being returned — toggle it on, and independently choose whether it's mandatory once shown, from Configuration → General.
Button colors & text
Two hex color fields (text and background) let you match the button to your brand — only the colors change; shape, padding and font always stay whatever your theme (Luma or Hyvä) already uses, so the button can never end up visually broken. An invalid hex value is simply ignored, falling back to the theme default. The button's text is also configurable, shown exactly as typed (case preserved, no automatic capitalization) — leave it empty to keep the default translated label.
reCAPTCHA protection
Return Manager registers itself as a protectable form in Magento's own native reCAPTCHA system — Stores → Configuration → Customers → Google reCAPTCHA → Storefront → "Enable for Return Manager". Whichever version you've already configured for the rest of the store (v2 checkbox, v2 invisible, or v3) applies automatically; there is no separate captcha configuration to maintain.
Admin grid & mass actions
Every request lands in Codingrow Extensions → Return Manager, paginated and filterable, with columns for order number, customer, receipt date, days elapsed (flagged past 14), custom field values, and status. Mass actions let you update the status of several selected requests at once, or delete rows to clean up test data.
| Status | Meaning |
|---|---|
| Pending | Just submitted, not yet reviewed. |
| Processing | Being handled by the store. |
| Complete | Return/refund finished. |
| Rejected | The store declined the request. |
| Cancelled | The customer withdrew their own request. |
Email templates & variables
Two native Magento email templates — a customer receipt (the durable-medium confirmation
required by law) and an internal admin notification — sent automatically via
TransportBuilder, exactly like Magento's own order emails. Clone either one from
Marketing → Email Templates, edit the wording with the native WYSIWYG editor,
then select your copy in Configuration → Email Templates — no custom
templating code involved.
| Variable | Content |
|---|---|
order_increment_id | The order number |
order_date | The order's own date, read automatically |
receipt_date | The date the customer declared receiving the goods |
days_since_receipt | Days elapsed since that date |
request_id | Internal reference number for this request |
submitted_at | Exact date and time the request was confirmed |
items_description | The optional free-text field, if enabled |
custom_fields_text | All filled-in custom fields, formatted as "Label: value" lines |
PDF return label
An optional simple slip (logo, sender name, return address, packaging instructions)
generated in-house with Zend_Pdf — the same PDF library Magento's own core uses
for invoices and shipments, no third-party dependency added — and attached automatically to
the customer's receipt email once enabled in Configuration → Return Label.
Upload a logo, fill in the return address and any packaging instructions, and every future
request's confirmation email carries a ready-to-print label with that request's own reference
number, order number, customer name and receipt date.
Placing the widget
The request link is never hardcoded into the theme — it's placed exclusively via Magento's native Widget system, so a merchant fully controls whether, and where, it appears. Two ways to do it, depending on how broadly you want it shown:
| Method | Best for |
|---|---|
| Content → Elements → Widgets | Showing the link on many/all pages at once, or in a fixed layout position (footer, sidebar) across the whole site. |
| Insert Widget inside a CMS page's content | Placing it on one specific page only — e.g. the homepage — exactly where you want it in that page's own content, without affecting any other page. |
Site-wide, via Content → Elements → Widgets:
- 1. Content → Elements → Widgets → Add Widget, choose the Return Manager link widget.
- 2. Assign it to "All Pages" or "Specified Page(s)" and set the display container (e.g.
contentorsidebar.additional) — on Hyvä themes, the "Footer" container may not be exposed to the widget picker; in that case use the main content area instead, right before the footer. - 3. Save and reload the target page(s) — no cache flush required for a newly saved widget instance.
On one specific page only, e.g. the homepage:
- 1. Content → Pages, open the page (e.g. "Home page").
- 2. In the Content tab's WYSIWYG editor, place the cursor where you want the button and click Insert Widget.
- 3. Choose the Return Manager link widget, set its label text and CSS class, then Insert — this drops a
{{widget type="Codingrow\ReturnManager\Block\Widget\Link" ...}}directive directly into that page's content, affecting only this page. - 4. Save the page.
License
Without a valid license key, the withdrawal page stays visible (a merchant should never be left without the legally-required button just because a license lapsed) but new submissions are blocked until a key is entered in Configuration → License → License Key.