Skip to content

Show "Renewal" for orders which are actually renewals#131

Open
mircobabini wants to merge 1 commit into
strangerstudios:devfrom
mircobabini:snippet/renewal-label-for-renewal-orders-only
Open

Show "Renewal" for orders which are actually renewals#131
mircobabini wants to merge 1 commit into
strangerstudios:devfrom
mircobabini:snippet/renewal-label-for-renewal-orders-only

Conversation

@mircobabini

Copy link
Copy Markdown
Member

Snippet to replace "Renewal" label logics showing "Renewal" for orders which are actually renewals.

Orders status column in admin shows a not clear "Renewal" label for returning customers (orders from a customer who already had an order before - might be a renewal or not).

Some people just want to see "Renewal" for orders which are actually renewals.

Community request: https://app.slack.com/client/T042RQSG0/C042RQSGW

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new PMPro “recipe” snippet to adjust the Orders admin list so the “Renewal” label only appears for orders considered true renewals (vs. any returning-customer order).

Changes:

  • Adds custom “Status” column output for PMPro orders list, including a conditional “Renewal” badge/link.
  • Implements renewal-detection logic for recurring and non-recurring orders.
  • Hides the default PMPro status column via admin CSS.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +8
* Replace "Renewal" label logics showing "Renewal" for orders which are actually renewals.
*
* Orders status column in admin shows a not clear "Renewal" label for returning customers
* (orders from a customer who already had an order before - might be a renewal or not).
*
* Some people just want to see "Renewal" for orders which are actually renewals.

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docblock wording is grammatically incorrect/unclear (e.g., “label logics”, “a not clear”). Please rephrase for clarity since these snippet headers are user-facing in the recipe library.

Suggested change
* Replace "Renewal" label logics showing "Renewal" for orders which are actually renewals.
*
* Orders status column in admin shows a not clear "Renewal" label for returning customers
* (orders from a customer who already had an order before - might be a renewal or not).
*
* Some people just want to see "Renewal" for orders which are actually renewals.
* Adjust the logic for the "Renewal" label so it is only shown for orders that are actual renewals.
*
* By default, the Orders status column in the admin shows a "Renewal" label for any returning customer
* (orders from a customer who has placed a previous order, whether or not it is an actual renewal).
*
* Use this recipe if you want the "Renewal" label to appear only for true subscription renewal orders.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +29
<span class="pmpro_order-status pmpro_order-status-<?php esc_attr_e( $order->status ); ?>">
<?php esc_html_e( ucwords( $order->status ) ); ?>

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

esc_attr_e()/esc_html_e() are translation-and-echo helpers; using them with dynamic values like $order->status can invoke the wrong text domain (default) and is not intended for non-translatable data. Use proper escaping (esc_attr/esc_html) and echo the result instead.

Suggested change
<span class="pmpro_order-status pmpro_order-status-<?php esc_attr_e( $order->status ); ?>">
<?php esc_html_e( ucwords( $order->status ) ); ?>
<span class="pmpro_order-status pmpro_order-status-<?php echo esc_attr( $order->status ); ?>">
<?php echo esc_html( ucwords( $order->status ) ); ?>

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +39
<?php if ( pmpro_order_is_renewal_in_subscription( $order ) ) { ?>
<a href="<?php echo esc_url( add_query_arg( array(
'page' => 'pmpro-orders',
's' => $order->subscription_transaction_id
), admin_url( 'admin.php' ) ) ); ?>"
title="<?php esc_attr_e( 'View all orders for this subscription', 'paid-memberships-pro' ); ?>"
class="pmpro_order-renewal"><?php esc_html_e( 'Renewal', 'paid-memberships-pro' ); ?></a>
<?php } ?>

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Renewal” link always searches by $order->subscription_transaction_id. For non-recurring renewals (where this field is empty) this renders a link with an empty s parameter, which won’t show the intended related orders. Consider only linking when a subscription transaction ID exists, or using a different query target for non-recurring renewals.

Suggested change
<?php if ( pmpro_order_is_renewal_in_subscription( $order ) ) { ?>
<a href="<?php echo esc_url( add_query_arg( array(
'page' => 'pmpro-orders',
's' => $order->subscription_transaction_id
), admin_url( 'admin.php' ) ) ); ?>"
title="<?php esc_attr_e( 'View all orders for this subscription', 'paid-memberships-pro' ); ?>"
class="pmpro_order-renewal"><?php esc_html_e( 'Renewal', 'paid-memberships-pro' ); ?></a>
<?php } ?>
<?php if ( pmpro_order_is_renewal_in_subscription( $order ) ) : ?>
<?php if ( ! empty( $order->subscription_transaction_id ) ) : ?>
<a href="<?php echo esc_url( add_query_arg( array(
'page' => 'pmpro-orders',
's' => $order->subscription_transaction_id,
), admin_url( 'admin.php' ) ) ); ?>"
title="<?php esc_attr_e( 'View all orders for this subscription', 'paid-memberships-pro' ); ?>"
class="pmpro_order-renewal"><?php esc_html_e( 'Renewal', 'paid-memberships-pro' ); ?></a>
<?php else : ?>
<span class="pmpro_order-renewal"><?php esc_html_e( 'Renewal', 'paid-memberships-pro' ); ?></span>
<?php endif; ?>
<?php endif; ?>

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +87
$sqlQuery = "SELECT `id`
FROM $wpdb->pmpro_membership_orders
WHERE `user_id` = '" . esc_sql( $order->user_id ) . "'
AND `id` <> '" . esc_sql( $order->id ) . "'
AND `gateway_environment` = '" . esc_sql( $order->gateway_environment ) . "'
AND `total` > 0
AND `total` IS NOT NULL
AND status NOT IN('refunded', 'review', 'token', 'error')
AND timestamp < '" . esc_sql( date( 'Y-m-d H:i:s', $order->timestamp ) ) . "'
LIMIT 1";

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-recurring renewal check builds SQL via string concatenation. Even with esc_sql(), this is error-prone and bypasses $wpdb->prepare() protections/type handling. Please switch to $wpdb->prepare() with placeholders and cast numeric fields (e.g., user_id/id) to integers.

Suggested change
$sqlQuery = "SELECT `id`
FROM $wpdb->pmpro_membership_orders
WHERE `user_id` = '" . esc_sql( $order->user_id ) . "'
AND `id` <> '" . esc_sql( $order->id ) . "'
AND `gateway_environment` = '" . esc_sql( $order->gateway_environment ) . "'
AND `total` > 0
AND `total` IS NOT NULL
AND status NOT IN('refunded', 'review', 'token', 'error')
AND timestamp < '" . esc_sql( date( 'Y-m-d H:i:s', $order->timestamp ) ) . "'
LIMIT 1";
$sqlQuery = $wpdb->prepare(
"SELECT `id`
FROM $wpdb->pmpro_membership_orders
WHERE `user_id` = %d
AND `id` <> %d
AND `gateway_environment` = %s
AND `total` > 0
AND `total` IS NOT NULL
AND status NOT IN('refunded', 'review', 'token', 'error')
AND timestamp < %s
LIMIT 1",
(int) $order->user_id,
(int) $order->id,
$order->gateway_environment,
date( 'Y-m-d H:i:s', (int) $order->timestamp )
);

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants