The real hooks, database schema, and meta keys available for integrating with return/exchange/cancel requests — e.g. a custom notification channel, a shipping-label generator triggered on approval, or a reporting dashboard.
1. Detecting the plugin is active
if ( defined( 'CR_WCREM_VERSION' ) ) {
// Safe to register the hooks below.
}
2. Lifecycle action hooks
Every meaningful moment in the request lifecycle already fires a plaindo_action() — hook these directly rather than polling the database.
wcrem_request_submittedaction
do_action( ‘wcrem_request_submitted’, int $order_id, string $req_type )
Fires immediately after a customer’s (or verified guest’s) return/exchange request is inserted. $req_type is 'return' or 'exchange'.
wcrem_new_request_emailaction
do_action( ‘wcrem_new_request_email’, int $order_id, string $req_type )
Fires alongside wcrem_request_submitted, specifically to trigger the admin notification email. Hook here for anything that should happen whenever you, the store owner, need to know about a new request — a Slack message, for instance.
wcrem_request_response_mailaction
do_action( ‘wcrem_request_response_mail’, int $order_id, string $req_type, string $response, string $coupon_code )
Fires after an admin accepts or declines a request. $response is 'accept' or the decline value; $coupon_code is set only when a return was accepted with a generated coupon.
add_action( 'wcrem_request_response_mail', function ( $order_id, $req_type, $response, $coupon_code ) {
if ( 'accept' !== $response || 'return' !== $req_type ) {
return;
}
// e.g. notify a fulfillment system that a returned item is expected back.
}, 10, 4 );
wcrem_before_guest_user_formaction
do_action( ‘wcrem_before_guest_user_form’ )
Fires immediately before the [wcrem_guest_user_form] shortcode renders its lookup form — useful for adding your own explanatory copy above it.
3. Customizing email content
Each of the plugin’s three emails exposes its own subject, heading, and body-message filters:| Subject filter | Heading filter | Message filter | |
|---|---|---|---|
| New request (to admin) | wcrem_new_request_email_subject |
wcrem_new_request_email_heading |
wcrem_new_request_message |
| Request received (to customer) | wcrem_request_email_subject |
wcrem_request_email_heading |
wcrem_request_message |
| Request response (to customer) | wcrem_request_email_subject |
wcrem_request_email_heading |
wcrem_request_response_message |
Note: the “request received” and “request response” emails currently share the same default subject/heading filter names and default text (“Return/Exchange Request”) — if you want those two emails to look distinct in an inbox, filter both explicitly rather than relying on the defaults, or set an explicit Subject in each email’s own WooCommerce → Settings → Emails screen instead.
Attachment size is also filterable:
add_filter( 'wcrem_attachment_max_size', function () {
return 10 * MB_IN_BYTES; // default is 5MB
} );
4. Reading request data
The tracking tables
| Table | Holds |
|---|---|
| {$wpdb->prefix}rem_requests | One row per request: user, order, type (r/e), status, dates, payment/coupon info, attachments (JSON). |
| {$wpdb->prefix}rem_requested_product | Line items of a request: which products, quantities, and per-item reason. |
| {$wpdb->prefix}rem_request_reason | Admin-defined canned reasons shown in the request form’s dropdown. |
global $wpdb;
$requests = $wpdb->get_results( $wpdb->prepare(
"SELECT r.*, rp.product_id, rp.quantity
FROM {$wpdb->prefix}rem_requests r
JOIN {$wpdb->prefix}rem_requested_product rp ON r.id = rp.request_id
WHERE r.order_id = %d",
$order_id
) );
Order & product meta
| Meta key | On | Meaning |
|---|---|---|
| _wcrem_return / _wcrem_exchange | Order line item | Set at checkout (woocommerce_thankyou) if that line item’s product is eligible. |
| _return_request_applied | Order | Guard flag preventing duplicate requests on the same order. |
| _exchange_request_order | Order | The ID of the child order created for an accepted exchange. |
| _wcrem_product_settings | Product | Serialized array with allow_return/allow_exchange — set via Product → Advanced. |
// Always via the order object — never get_post_meta()/update_post_meta(),
// which silently break under HPOS (High-Performance Order Storage).
$order = wc_get_order( $order_id );
$exchange_order_id = $order->get_meta( '_exchange_request_order' );
5. Best practices
- Never touch order data with
get_post_meta()/update_post_meta(). Always go through$order->get_meta()/update_meta_data()/save(). - Don’t edit any file inside the base plugin. A direct patch won’t survive an update — use the hooks above instead.
- Check
$req_typeexplicitly in any hook you attach to — several fire for both returns and exchanges with the same signature. - Sanitize and escape exactly as you would anywhere else in WordPress — none of these hooks do it for you.
6. Worked example
A minimal companion plugin that posts to a Slack webhook whenever a return is accepted:<?php
/**
* Plugin Name: RMA — Slack Notifications
* Description: Posts to Slack when a return request is accepted.
* Requires Plugins: woocommerce-return-management
*/
if ( ! defined( 'CR_WCREM_VERSION' ) ) {
return;
}
add_action( 'wcrem_request_response_mail', function ( $order_id, $req_type, $response, $coupon_code ) {
if ( 'accept' !== $response || 'return' !== $req_type ) {
return;
}
$order = wc_get_order( $order_id );
$message = sprintf(
'Return accepted for order #%d (%s)%s',
$order_id,
$order->get_billing_email(),
$coupon_code ? " — coupon issued: {$coupon_code}" : ''
);
wp_remote_post( 'https://hooks.slack.com/services/...', array(
'body' => wp_json_encode( array( 'text' => $message ) ),
'headers' => array( 'Content-Type' => 'application/json' ),
) );
}, 10, 4 );
