Wo WooCommerce Beginner

Return Portal + Auto-Label — Complete Documentation

Self-service customer return portal with multi-carrier labels, admin inspection, and automatic resolution for WooCommerce.

Updated Module version 1.0.7

Self-service customer return portal, automatically generated multi-carrier return labels, admin inspection workflow, and resolution engine (refund, bonus store credit, replacement) for WooCommerce.

Version: 1.0.7
Compatibility: WordPress 6.2+ • WooCommerce 8.0+ • PHP 8.0+ • HPOS and Cart/Checkout Blocks

Overview

Return Portal + Auto-Label automates the entire lifecycle of a product return for your WooCommerce store:

  • Customer side: the customer requests their return without contacting support, selects items, chooses a reason, and immediately receives their PDF label.
  • Admin side: dashboard with timeline, line-by-line inspection, complete activity log, and automatic resolution.
  • 6 carriers: Manual (native PDF), Colissimo, Mondial Relay, Chronopost, UPS, DPD.
  • 3 resolutions: native WooCommerce refund, bonus store credit (+X%), or automatic replacement.

Return statuses

A return moves through up to 7 stages:

Status Description
requested Request received, awaiting validation
approved Approved by admin (or auto-approved under threshold)
label_sent Label generated and sent to customer
in_transit Package being shipped
received Package received at warehouse
inspecting Items being inspected
resolved Resolution applied (refund / credit / replacement)

Two additional terminal statuses: rejected and cancelled.

Installation

Method 1 — Via WordPress admin

  1. Download the dfreturnportal.zip file.
  2. In WordPress, go to Plugins → Add New → Upload Plugin.
  3. Select the ZIP, click Install Now.
  4. Activate the plugin.

Method 2 — Via FTP/SSH

cd wp-content/plugins/
unzip dfreturnportal.zip
# Then activate from WordPress admin

Post-installation checks

  • A Returns menu appears in the WordPress sidebar.
  • An endpoint /my-account/returns/ is automatically created.
  • The custom tables wp_dfrp_returns, wp_dfrp_return_items, wp_dfrp_history, wp_dfrp_attachments are created.

If the “Returns” tab doesn’t appear in My Account, go to Settings → Permalinks and click “Save” to refresh rewrite rules.

Initial configuration

Go to Returns → Settings.

General

Setting Description
Eligibility window Number of days after the order during which a return is allowed. Default: 30 days.
Customer portal page WordPress page where the [dfrp_portal] shortcode will be displayed. Optional if you only use the My Account endpoint.
Admin notifications Email address that will receive notifications of new requests. Default: site admin.

Carrier

Select the active carrier from the 6 available. You can also configure the label format (A4, A5, A6, 10×15).

Return address

Enter the physical address where return packages will be sent. Required to generate labels. Fields: Company, Street, City, Postcode, Country (ISO 2-letter code), Phone, Email.

Carrier credentials

For each API carrier (Colissimo, Mondial Relay, etc.), a collapsible block contains the required credentials. Only fill in the credentials for the carrier you actually use.

Resolution

Setting Description
Store credit bonus (%) Percentage added to the refund amount when the customer chooses bonus store credit. Default: 10%.
Auto-approval threshold Below this amount (shop currency), requests are auto-approved and the label is generated without admin intervention. Set to 0 to disable.
Proposed resolution by reason For each reason (8 default reasons), choose the proposed resolution: refund / bonus credit / replacement.

Exclusions

  • Excluded categories: WooCommerce IDs separated by commas. Products in these categories will never be eligible for return.
  • Excluded SKUs: one SKU per line.

Customer experience

Via the My Account page (logged-in customers)

The simplest and most-used flow. The Returns tab appears automatically in the /my-account/ menu next to “Orders”, “Addresses”, etc.

The customer clicks Returns, sees the list of their eligible orders (no need to enter email/number), clicks Start a Return on the relevant order, selects items, chooses a reason and quantity per item, optionally adds photos (if the reason requires it), chooses their preferred resolution, and immediately receives an RMA number (e.g. RMA-20260523-A1B2C3) plus a confirmation email.

Via a public page (guest customers)

Create a WordPress page, insert the shortcode:

[dfrp_portal]

The customer will need to enter their order number + email to authenticate. The rest of the flow is identical.

Track an existing request

On the public portal page, a “Track an existing request” block lets guest customers check their RMA status (status, carrier tracking number, link to the label).

Shortcode customization

[dfrp_portal title="Return Request" context="page"]
Attribute Values Description
title free text Portal title (rarely used visually).
context page or myaccount Force the context. myaccount skips the lookup step for logged-in users.

Admin workflow

Dashboard

Accessible via Returns → Dashboard. Contains 9 colored statistics cards (count by status, clickable to filter the list), the 10 latest RMAs with quick detail access, and a customer portal URL banner with a “Copy” button to share.

Request list

Accessible via Returns → All Requests. Table with filters by status, free-text search (RMA, customer email, order number), and pagination (20 per page).

Request detail page

Components:

  1. Header: RMA code + status badge + back to list.
  2. Timeline: 7 colored dots showing visual progress.
  3. Items to return: table with product, SKU, quantity, unit price, reason, and per-item inspection (dropdown Approved / Partially / Rejected — activated after received status).
  4. Customer photos: gallery if the customer uploaded supporting evidence.
  5. Activity log: complete chronological history.
  6. Information: customer email, order link, resolution preference, customer note.
  7. Return label: carrier, tracking number, download PDF button, regenerate button.
  8. Actions: “Move to: [next status]” buttons according to the state machine.
  9. Resolve (visible if status is received or inspecting): resolution selector + “Apply” button.

Allowed transitions

The state machine prevents invalid transitions:

requested  → approved | rejected | cancelled
approved   → label_sent | rejected | cancelled
label_sent → in_transit | cancelled
in_transit → received
received   → inspecting
inspecting → resolved | rejected

The statuses resolved, rejected and cancelled are terminal.

Auto-approval

If you have configured an auto-approval threshold (e.g. €50), any request whose total amount is less than or equal to the threshold is automatically moved from requested to approved, the label is generated immediately and sent to the customer, with no admin intervention required.

Supported carriers

Manual (no API)

Ideal to start with. Generates a native PDF slip with QR code, with no external API dependency. Zero configuration, free, works immediately. Limitation: no automatic tracking. Usage: the customer prints it, you put it in the package on initial shipment, or they tape it on for classic postal returns.

Colissimo (La Poste)

Official REST API (Sls Service generateLabel). Required credentials: Contract Number, Password. Specifics: generates a parcelNumber barcode, return type set to “3”, default PDF format.

Mondial Relay

SOAP API (WSI4_CreationEtiquette). Required credentials: Brand code, Private Key, Pickup Point. Specifics: CCC collection mode (Customer-Entrusted Parcel), MD5 signature required.

Chronopost

SOAP API (shippingMultiParcelV5). Required credentials: Account Number, Password, Subaccount. Specifics: Product Code 8R (Relais return), return mode 2.

UPS

REST API v2403 (/ship). Required credentials: Client ID (OAuth2), Client Secret, Shipper Number. Specifics: ReturnService.Code = 8 (Electronic Return Label), default base64 GIF format.

DPD

REST API (cargonet endpoint). Required credentials: Username, Password, Customer ID. Specifics: Basic Auth, PDF A6 format.

Resolutions

Refund

Uses WooCommerce’s native wc_create_refund() function. Re-credits the original payment method, automatic restock (configurable), creates a refund note on the order, and triggers a native WooCommerce confirmation email.

Bonus store credit

Automatically creates a WooCommerce coupon:

  • Amount = return total + bonus (configurable %, default 10%).
  • Email restriction: usable only by the customer’s email.
  • Expiration: 6 months by default.
  • Single use.

The customer receives an email with their coupon code in large type.

Replacement

Creates a new WooCommerce order at €0 (free for the customer). Shipping/billing addresses copied from the original order, items identical to the approved returned items, initial status processing (you ship it normally). The customer receives an email with the new order number.

Automatic proposal

The engine analyzes returned-item reasons and proposes the most relevant resolution. Configuration in Returns → Settings → Proposed resolution by reason. Default mapping:

Reason Proposed resolution
Damaged item Replacement
Defective item Replacement
Wrong item received Replacement
Matches description but doesn’t fit Refund
Changed mind Bonus credit
Wrong size or color Bonus credit
Late delivery Refund
Other Refund

Customization

Template overrides

All email templates are overridable via your theme. Copy the source file templates/emails/*.php to yourtheme/dfreturnportal/emails/*.php.

Hooks (actions)

do_action('dfrp_after_return_created', int $returnId, array $return);
do_action('dfrp_status_changed', int $returnId, string $fromStatus, string $toStatus);
do_action('dfrp_label_generated', int $returnId, array $label);
do_action('dfrp_before_resolution', int $returnId, string $resolution);
do_action('dfrp_after_resolution', int $returnId, string $resolution, array $result);

Filters

// Customize eligible order statuses (default: ['completed', 'processing'])
add_filter('dfrp_eligible_order_statuses', function($statuses) {
    $statuses[] = 'on-hold';
    return $statuses;
});

// Customize return reasons
add_filter('dfrp_reasons', function($reasons) {
    $reasons[] = [
        'code'          => 'custom_reason',
        'label'         => 'My custom reason',
        'require_photo' => false,
    ];
    return $reasons;
});

// Customize My Account endpoint slug (default: 'returns')
add_filter('dfrp_myaccount_endpoint', function() {
    return 'my-returns';
});

// Customize My Account menu label
add_filter('dfrp_myaccount_menu_label', function() {
    return 'My product returns';
});

// Add a custom carrier
add_filter('dfrp_register_carriers', function($carriers) {
    $carriers[] = new MyCustomCarrier();
    return $carriers;
});

Clean uninstallation

By default, uninstallation preserves data (tables and options). To purge everything on uninstall, add to wp-config.php:

define('DFRP_DELETE_DATA_ON_UNINSTALL', true);

REST API

All endpoints are under the dfrp/v1 namespace. Base URL: https://yoursite.com/wp-json/dfrp/v1/.

Public endpoints

Endpoint Method Description
/lookup POST Look up an order by number + email.
/create POST Create a new return request.
/track POST Track an RMA via code + email.
/upload-photo POST Upload a supporting photo (multipart).

Logged-in customer endpoints

Endpoint Method Description
/my-orders GET List eligible orders of the logged-in customer.

Admin endpoints (capability manage_woocommerce)

Endpoint Method Description
/admin/returns GET Paginated list with filters.
/admin/returns/{id} GET Return detail.
/admin/returns/{id}/transition POST Change status.
/admin/returns/{id}/inspect-item POST Item inspection result.
/admin/returns/{id}/resolve POST Apply a resolution.
/admin/returns/{id}/regenerate-label POST Regenerate the label.

Troubleshooting

The portal shows “Loading…” indefinitely

  • Check the browser console (F12) — you should see [Return Portal] script frontend.js executed.
  • If nothing appears, a security plugin (Wordfence, Sucuri, NinjaFirewall) is blocking the inline script. Temporarily disable it to test.
  • Also check JS optimizers (WP Rocket “Delay JS”, Autoptimize, Cloudflare Rocket Loader) — the plugin already emits the necessary opt-out attributes, but very aggressive configurations may still block.

The “Returns” tab doesn’t appear in My Account

Go to Settings → Permalinks and click “Save Changes” (without changing anything). This forces WordPress to regenerate rewrite rules.

“Constant DFRP_VERSION already defined” error

The plugin folder is duplicated. Check:

ls -la wp-content/plugins/ | grep dfreturnportal

Delete duplicate copies (e.g. dfreturnportal-old/, dfreturnportal-1/).

Customers don’t receive emails

  • Make sure email sending works globally.
  • Set up a proper SMTP (WP Mail SMTP, FluentSMTP).
  • Check the recipient domain’s spam logs.

The PDF label is empty or corrupt

  • Make sure the return address is fully filled in.
  • For API carriers, validate credentials in test mode first.
  • Check PHP logs (/wp-content/debug.log if WP_DEBUG_LOG is active).

FAQ

Does the plugin require a carrier subscription?
No. The Manual mode generates a native PDF slip without any API dependency. API modes (Colissimo, etc.) are optional.

HPOS (High-Performance Order Storage) compatible?
Yes, fully. The plugin declares its compatibility at WooCommerce startup.

Cart/Checkout Blocks compatible?
Yes.

Are product variations handled?
Yes, each variation is treated as a distinct item.

And virtual or downloadable products?
They are automatically excluded from returns.

Can the customer partially return an order?
Yes. Eligibility takes into account quantities already returned via previous RMAs.

Multi-language?
The plugin is translation-ready (Text Domain dfreturnportal, .pot file provided). Compatible with WPML, Polylang, TranslatePress.

Are customer photos stored securely?
Yes, in the WordPress media library with .htaccess rules preventing directory listing.

Was this page helpful?

Still stuck? Contact support