Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/sync-file-list.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
wpeverest/user-registration-pro@master:
wpeverest/user-registration-pro@UR-2654-feature/fixed-period-membership:
- assets
- includes
- modules
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Sync Files To Pro
on:
push:
branches:
- master
- UR-2654-feature/fixed-period-membership
workflow_dispatch:
jobs:
sync:
Expand Down
17 changes: 17 additions & 0 deletions assets/extensions-json/all-features.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,23 @@
"demo_video_url": "",
"released_date": "01/08/2024"
},
{
"title": "Fixed Period Membership",
"slug": "user-registration-fixed-period-membership",
"name": "User Registration Fixed Period Membership",
"image": "extensions-json/sections/icons/membership.png",
"excerpt": "Set a fixed expiration date for paid memberships, with optional annual renewal to automatically advance the expiry date each year.",
"category": "Membership",
"link": "https://docs.wpuserregistration.com/docs/fixed-period-membership/?utm_source=dashboard-all-features&utm_medium=card-documentation-link",
"plan": [
"plus",
"professional",
"themegrill agency"
],
"setting_url": "",
"demo_video_url": "",
"released_date": "04/15/2026"
},
{
"title": "Custom Email",
"slug": "user-registration-custom-email",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,21 @@
post_meta_data.amount = form
.find("#ur-membership-amount")
.val();
if (post_meta_data.type === "paid") {
post_meta_data.enable_fixed_period_duration = form
.find("#urm_enable_fixed_period_duration")
.is(":checked");

post_meta_data.fixed_period = {
period_type: form
.find("input[name=\"urm_fixed_period_duration_type\"]:checked")
.val(),
expiration_date: form.find("#urm_fixed_expiration_date").val(),
expiration_date_renewal: form
.find("#urm_fixed_expiration_date_renewal")
.is(":checked")
};
}
var is_paypal_selected = form
.find("#ur-membership-pg-paypal:checked")
.val(),
Expand Down Expand Up @@ -1544,13 +1559,18 @@
team_pricing_container.removeClass("ur-d-flex");
team_pricing_container.addClass("ur-d-none");
payment_notice.addClass("ur-d-none");

var membership_fixed_period_container = $(".ur-membership-fixed-period-main-container");
membership_fixed_period_container.addClass("ur-d-none");

sub_container.show();
if ("free" !== val) {
if ("paid" === val) {
sub_container.hide();
if (!paidConfigured) {
payment_notice.removeClass("ur-d-none");
}
membership_fixed_period_container.removeClass("ur-d-none");
} else {
sub_container.removeClass("ur-d-none");
membership_duration_period.removeClass("ur-d-none");
Expand All @@ -1575,6 +1595,15 @@
}
);

$(document).on("click", "#urm_enable_fixed_period_duration", function () {
var membership_fixed_period_settings_container = $(".ur-membership-fixed-period-settings-container");
if ($(this).is(":checked")) {
membership_fixed_period_settings_container.removeClass("ur-d-none");
} else {
membership_fixed_period_settings_container.addClass("ur-d-none");
}
});

$(document).on("click", "#ur-membership-upgrade-action", function () {
$("#upgrade-settings-container").toggle();
$("input:radio[name=ur_membership_type]:checked").trigger("click");
Expand Down
12 changes: 12 additions & 0 deletions includes/class-ur-cron.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* @see UR_Cron::weekly_events()
*/
public function __construct() {
add_filter( 'cron_schedules', array( $this, 'add_schedules' ) );

Check warning on line 33 in includes/class-ur-cron.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Detected changing of cron_schedules, but could not detect the interval value.
add_action( 'init', array( $this, 'schedule_events' ) );
}

Expand Down Expand Up @@ -72,13 +72,13 @@
wp_schedule_event( time(), 'biweekly', 'user_registration_usage_stats_scheduled_events' );
}

if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_membership_renewal_check' ) && ur_check_module_activation('membership') && ur_option_checked( 'user_registration_membership_enable_renewal_reminder_user_email', true ) ) {

Check failure on line 75 in includes/class-ur-cron.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Expected 1 spaces before closing parenthesis; 0 found

Check failure on line 75 in includes/class-ur-cron.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Expected 1 spaces after opening parenthesis; 0 found
wp_schedule_event( time(), 'daily', 'urm_daily_membership_renewal_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_membership_expiring_soon_check' ) && ur_check_module_activation('membership') && ur_option_checked( 'user_registration_membership_enable_expiring_soon_user_email', true ) ) {

Check failure on line 78 in includes/class-ur-cron.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Expected 1 spaces before closing parenthesis; 0 found

Check failure on line 78 in includes/class-ur-cron.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Expected 1 spaces after opening parenthesis; 0 found
wp_schedule_event( time(), 'daily', 'urm_daily_membership_expiring_soon_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_membership_ended_check' ) && ur_check_module_activation('membership') && ur_option_checked( 'user_registration_membership_enable_membership_ended_user_email', true ) ) {

Check failure on line 81 in includes/class-ur-cron.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Expected 1 spaces before closing parenthesis; 0 found

Check failure on line 81 in includes/class-ur-cron.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Expected 1 spaces after opening parenthesis; 0 found
wp_schedule_event( time(), 'daily', 'urm_daily_membership_ended_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_run_delayed_subscription' ) ) {
Expand All @@ -87,6 +87,18 @@
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_membership_expiration_check' ) ) {
wp_schedule_event( time(), 'daily', 'urm_daily_membership_expiration_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_fixed_period_membership_renewal_check' ) && ur_check_module_activation( 'fixed-period-membership' ) && ur_option_checked( 'user_registration_membership_enable_renewal_reminder_user_email', true ) ) {
wp_schedule_event( time(), 'daily', 'urm_daily_fixed_period_membership_renewal_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_fixed_period_membership_expiring_soon_check' ) && ur_check_module_activation( 'fixed-period-membership' ) && ur_option_checked( 'user_registration_membership_enable_expiring_soon_user_email', true ) ) {
wp_schedule_event( time(), 'daily', 'urm_daily_fixed_period_membership_expiring_soon_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_fixed_period_membership_ended_check' ) && ur_check_module_activation( 'fixed-period-membership' ) && ur_option_checked( 'user_registration_membership_enable_membership_ended_user_email', true ) ) {
wp_schedule_event( time(), 'daily', 'urm_daily_fixed_period_membership_ended_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_fixed_period_membership_expiration_check' ) && ur_check_module_activation( 'fixed-period-membership' ) ) {
wp_schedule_event( time(), 'daily', 'urm_daily_fixed_period_membership_expiration_check' );
}
if ( UR_PRO_ACTIVE && ! wp_next_scheduled( 'urm_daily_payment_retry_check' ) ) {
wp_schedule_event( time(), 'daily', 'urm_daily_payment_retry_check' );
}
Expand Down
1 change: 1 addition & 0 deletions includes/class-ur-smart-tags.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
* @return array array of smart tags.
*/
public static function smart_tags_list() {
if ( isset( $_GET['page'] ) && $_GET['page'] === 'yith_wpv_panel' &&

Check failure on line 44 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Use Yoda Condition checks, you must.

Check warning on line 44 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Processing form data without nonce verification.

Check warning on line 44 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Processing form data without nonce verification.
isset( $_GET['tab'] ) && $_GET['tab'] === 'vendors' &&

Check failure on line 45 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Use Yoda Condition checks, you must.

Check warning on line 45 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Processing form data without nonce verification.

Check warning on line 45 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Processing form data without nonce verification.
isset( $_GET['sub_tab'] ) && $_GET['sub_tab'] === 'vendors-list' ) {

Check failure on line 46 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Use Yoda Condition checks, you must.

Check warning on line 46 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Processing form data without nonce verification.

Check warning on line 46 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Processing form data without nonce verification.
$smart_tags = array();
} else {
$smart_tags = array_merge( self::ur_unauthenticated_parsable_smart_tags_list(), self::ur_authenticated_parsable_smart_tags_list() );
Expand Down Expand Up @@ -168,12 +168,12 @@
$user_data = UR_Emailer::user_data_smart_tags( $values['email'] );

if ( ! empty( $values['context'] ) && 'thank_you_page' == $values['context'] ) {
$subscription_service = new SubscriptionService();

Check warning on line 171 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Equals sign not aligned with surrounding assignments; expected 8 spaces but found 1 space
$user_data['member_id'] = $values['member_id'];

Check warning on line 172 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Equals sign not aligned with surrounding assignments; expected 6 spaces but found 7 spaces
$user_data['context'] = $values['context'];
$user_data['transaction_id'] = ! empty( $values['transaction_id'] ) ? $values['transaction_id'] : '';
$values = array(

Check warning on line 175 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Equals sign not aligned with surrounding assignments; expected 22 spaces but found 6 spaces
'membership_tags' => $subscription_service->get_membership_plan_details( $user_data )

Check failure on line 176 in includes/class-ur-smart-tags.php

View workflow job for this annotation

GitHub Actions / Code sniff (PHP 7.4, WP Latest)

Each array item in a multi-line array declaration must end in a comma
);
}

Expand Down Expand Up @@ -743,6 +743,7 @@
case 'membership_plan_next_billing_date':
case 'membership_plan_expiry_date':
case 'membership_plan_status':
case 'renewal_link':
case 'membership_renewal_link':
case 'membership_cancellation_date':
if ( isset( $values[ $other_tag ] ) ) {
Expand Down
37 changes: 30 additions & 7 deletions modules/membership/includes/AJAX.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,15 @@ public static function register_member() {
if ( in_array( $data['payment_method'], array( 'free', 'bank' ) ) ) {
delete_user_meta( $member_id, 'urm_user_just_created' );
}

do_action(
'urm_after_register_member',
array(
'response' => $response,
'membership_id' => $data['membership'],
)
);

wp_send_json_success( $response );
} else {
$message = isset( $response['message'] ) ? $response['message'] : esc_html__( 'Sorry! There was an unexpected error while registering the user . ', 'user-registration' );
Expand Down Expand Up @@ -1136,13 +1145,27 @@ public static function confirm_payment() {
}

if ( $is_renewing ) {
$response['message'] = __( 'Membership has been successfully renewed.', 'user-registration' );
$subscription_service = new SubscriptionService();
$members_subscription_repo = new MembersSubscriptionRepository();
$membership_repository = new MembershipRepository();
$member_subscription = $members_subscription_repo->get_subscription_data_by_member_and_membership_id( $member_id, $current_membership_id );
$membership = $membership_repository->get_single_membership_by_ID( $member_subscription['item_id'] );
$membership_metas = wp_unslash( json_decode( $membership['meta_value'], true ) );
$response['message'] = __( 'Membership has been successfully renewed.', 'user-registration' );

$members_subscription_repo = new MembersSubscriptionRepository();
$membership_repository = new MembershipRepository();
$member_subscription = $members_subscription_repo->get_subscription_data_by_member_and_membership_id( $member_id, $current_membership_id );

$membership = $membership_repository->get_single_membership_by_ID( $member_subscription['item_id'] );
$membership_metas = wp_unslash( json_decode( $membership['meta_value'], true ) );

// Route to fixed-period service when applicable; fall back to standard service.
$is_paid = isset( $membership_metas['type'] ) && 'paid' === $membership_metas['type'];
$is_fixed_period = ! empty( $membership_metas['enable_fixed_period_duration'] );
$is_renewable = ! empty( $membership_metas['fixed_period']['expiration_date_renewal'] );
$is_fixed_period_addon_active = class_exists( '\WPEverest\URM\FixedPeriodMemebership\FixedPeriodSubscriptionService' );

if ( $is_paid && $is_fixed_period && $is_renewable && $is_fixed_period_addon_active ) {
$subscription_service = new \WPEverest\URM\FixedPeriodMemebership\FixedPeriodSubscriptionService();
} else {
$subscription_service = new SubscriptionService();
}

$membership_metas['post_title'] = $membership['post_title'];
$subscription_service->update_subscription_data_for_renewal( $member_subscription, $membership_metas );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,4 +321,41 @@ public function get_subscription_by_subscription_id_meta( $subscription_id ) {

return $result ? $result : false;
}

/**
* Return all subscriptions with an active, trial, or pending status.
*
* Used by the fixed-period membership service to find subscriptions that
* may need expiration processing without scanning the entire table.
*
* @return array Array of subscription rows.
*/
public function get_active_subscriptions() {
$sql = $this->wpdb()->prepare(
"SELECT wu.user_email,
wu.user_login AS username,
wu.ID AS member_id,
wp.post_title AS membership_plan_name,
wums.item_id AS membership,
wums.ID AS subscription_id,
wums.user_id,
wums.status,
wums.next_billing_date,
wums.expiry_date,
wums.billing_cycle,
wums.billing_amount,
wums.start_date
FROM {$this->table} wums
LEFT JOIN {$this->users_table} wu ON wums.user_id = wu.ID
LEFT JOIN {$this->posts_table} wp ON wums.item_id = wp.ID
WHERE wums.status IN (%s, %s, %s)",
'active',
'trial',
'pending'
);

$result = $this->wpdb()->get_results( $sql, ARRAY_A );

return $result ? $result : array();
}
}
12 changes: 8 additions & 4 deletions modules/membership/includes/Admin/Services/EmailService.php
Original file line number Diff line number Diff line change
Expand Up @@ -530,9 +530,11 @@ public function send_membership_expiring_soon_email( $data ) {
$form_id = ur_get_form_id_by_userid( $data['member_id'] );
$settings = new UR_Settings_Membership_Expiring_Soon_User_Email();
$subscription_service = new SubscriptionService();
$tags = $subscription_service->get_membership_plan_details( $data );
$values = array( 'membership_tags' => $subscription_service->get_membership_plan_details( $data ) );
$values = $data + $values;

$message = apply_filters( 'user_registration_process_smart_tags', get_option( 'user_registration_membership_expiring_soon_user_email_message', $settings->user_registration_get_membership_expiring_soon_user_email() ), $tags, $form_id );
$message = apply_filters( 'user_registration_process_smart_tags', get_option( 'user_registration_membership_expiring_soon_user_email_message', $settings->user_registration_get_membership_expiring_soon_user_email() ), $values, $form_id );
$subject = \UR_Emailer::parse_smart_tags( $subject, $values );

$message = apply_filters( 'ur_membership_expiring_soon_email_custom_template', $message, $subject );

Expand Down Expand Up @@ -562,9 +564,11 @@ public function send_membership_ended_email( $data ) {
$form_id = ur_get_form_id_by_userid( $data['member_id'] );
$settings = new UR_Settings_Membership_Ended_User_Email();
$subscription_service = new SubscriptionService();
$tags = $subscription_service->get_membership_plan_details( $data );
$values = array( 'membership_tags' => $subscription_service->get_membership_plan_details( $data ) );
$values = $data + $values;

$message = apply_filters( 'user_registration_process_smart_tags', get_option( 'user_registration_membership_ended_user_email_message', $settings->user_registration_get_membership_ended_user_email() ), $tags, $form_id );
$message = apply_filters( 'user_registration_process_smart_tags', get_option( 'user_registration_membership_ended_user_email_message', $settings->user_registration_get_membership_ended_user_email() ), $values, $form_id );
$subject = \UR_Emailer::parse_smart_tags( $subject, $values );

$message = apply_filters( 'ur_membership_membership_ended_email_custom_template', $message, $subject );

Expand Down
15 changes: 12 additions & 3 deletions modules/membership/includes/Admin/Services/SubscriptionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,16 @@ public function get_membership_plan_details( $data ) {
$billing_cycle = ( 'subscription' === $membership_metas['type'] ) ? ( ( 'day' === $membership_metas['subscription']['duration'] ) ? esc_html( 'Daily', 'user-registration' ) : ( esc_html( ucfirst( $membership_metas['subscription']['duration'] . 'ly' ) ) ) ) : 'N/A';
$trial_period = ( 'subscription' === $membership_metas['type'] && 'on' === $order['trial_status'] ) ? ( $membership_metas['trial_data']['value'] . ' ' . $membership_metas['trial_data']['duration'] . ( $membership_metas['trial_data']['value'] > 1 ? 's' : '' ) ) : 'N/A';

$next_billing_date = 'subscription' === $membership_metas['type'] && ! empty( $subscription['next_billing_date'] ) ? date( 'Y, F d', strtotime( $subscription['next_billing_date'] ) ) : 'N/A';
$expiry_date = 'subscription' === $membership_metas['type'] && ! empty( $subscription['expiry_date'] ) ? date( 'Y, F d', strtotime( $subscription['expiry_date'] ) ) : 'N/A';
$is_fixed_period_paid = 'paid' === $membership_metas['type'] && ! empty( $membership_metas['enable_fixed_period_duration'] );
$is_valid_date = function( $date ) {
return ! empty( $date ) && '0000-00-00 00:00:00' !== $date && '0000-00-00' !== $date;
};
$next_billing_date = ( 'subscription' === $membership_metas['type'] || $is_fixed_period_paid ) && $is_valid_date( $subscription['next_billing_date'] ?? '' )
? date( 'Y, F d', strtotime( $subscription['next_billing_date'] ) )
: ( $is_fixed_period_paid && $is_valid_date( $data['next_billing_date'] ?? '' ) ? date( 'Y, F d', strtotime( $data['next_billing_date'] ) ) : 'N/A' );
$expiry_date = ( 'subscription' === $membership_metas['type'] || $is_fixed_period_paid ) && $is_valid_date( $subscription['expiry_date'] ?? '' )
? date( 'Y, F d', strtotime( $subscription['expiry_date'] ) )
: ( $is_fixed_period_paid && $is_valid_date( $data['expiry_date'] ?? '' ) ? date( 'Y, F d', strtotime( $data['expiry_date'] ) ) : 'N/A' );
$trial_start_date = 'subscription' === $membership_metas['type'] && 'on' === $order['trial_status'] && ! empty( $subscription['trial_start_date'] ) ? date( 'Y, F d', strtotime( $subscription['trial_start_date'] ) ) : 'N/A';
$trial_end_date = 'subscription' === $membership_metas['type'] && 'on' === $order['trial_status'] && ! empty( $subscription['trial_end_date'] ) ? date( 'Y, F d', strtotime( $subscription['trial_end_date'] ) ) : 'N/A';
$membership_type = ucwords( $membership_metas['type'] ) == 'Paid' ? __( 'One-Time Payment', 'user-registration' ) : ucwords( $membership_metas['type'] );
Expand Down Expand Up @@ -421,7 +429,8 @@ public function get_membership_plan_details( $data ) {
),
'membership_plan_coupon' => esc_html( $order['coupon'] ?? '' ),
'membership_plan_total' => ( ! empty( $currencies[ $currency ]['symbol_pos'] ) && 'left' === $currencies[ $currency ]['symbol_pos'] ) ? $symbol . number_format( $total, 2 ) : number_format( $total, 2 ) . $symbol,
'membership_renewal_link' => "<a href=$membership_tab_url>" . __( 'Renew Now', 'user-registration' ) . '</a>',
'renewal_link' => $membership_tab_url,
'membership_renewal_link' => '<a href="' . $membership_tab_url . '">' . __( 'Renew Now', 'user-registration' ) . '</a>',
'membership_plan_transaction_id' => ! empty( $data['transaction_id'] ) ? $data['transaction_id'] : '',
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,5 +264,6 @@ class="user-registration-switch__control hide-show-check enabled"
WPEverest\URMembership\Local_Currency\Admin\CoreFunctions::ur_render_local_currency_settings( $membership_details );
endif;
?>

</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,38 @@ class="ur-subscription-fields <?php echo isset( $membership_details['type'] ) &&

<?php
do_action( 'ur_membership_team_membership', $membership, $membership_details );

// When the fixed-period module is not active, show a locked Enable Expiration toggle.
if ( ! ur_check_module_activation( 'fixed-period-membership' ) || ! class_exists( 'WPEverest\URM\FixedPeriodMemebership\Admin' ) ) :
?>
<div class="ur-membership-fixed-period-main-container <?php echo ( isset( $membership_details['type'] ) && 'paid' === $membership_details['type'] ) ? '' : 'ur-d-none'; ?>">
<div class="ur-membership-fixed-period-enable-container ur-d-flex ur-mt-2 ur-align-items-start upgradable-type" style="gap:20px; margin-bottom:16px;">
<div class="ur-label" style="width:30%; padding-top:4px;">
<label for="urm_enable_fixed_period_duration"><?php esc_html_e( 'Enable Expiration :', 'user-registration' ); ?></label>
</div>
<div style="width:100%">
<div class="ur-toggle-section m1-auto">
<span class="user-registration-toggle-form">
<input
data-key-name="Fixed period duration Action"
id="urm_enable_fixed_period_duration"
type="checkbox"
class="user-registration-switch__control hide-show-check enabled"
disabled
<?php echo ! empty( $membership_details['enable_fixed_period_duration'] ) ? 'checked' : ''; ?>
>
<span class="slider round" style="opacity: 0.5;"></span>
<?php ur_render_premium_feature_gate(); ?>
</span>
</div>
<p style="margin:4px 0 0; color:#757575; font-size:12px; line-height:1.5;">
<?php esc_html_e( 'Set a fixed end date for this membership. When enabled, access is granted only until the specified expiration date instead of lifetime access.', 'user-registration' ); ?>
</p>
</div>
</div>
</div>
<?php
endif;
?>

<!-- Payment Settings Notice -->
Expand Down
26 changes: 25 additions & 1 deletion templates/myaccount/membership.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@
$membership_type = $membership['post_content']['type'];
}
$can_renew = ! $is_renewing && isset( $membership['post_content']['type'] ) && 'automatic' !== $data['renewal_behaviour'] && 'subscription' == $membership_type;

// Fixed-period paid memberships with annual renewal enabled (pro + module required).
if ( UR_PRO_ACTIVE
&& ur_check_module_activation( 'fixed-period-membership' )
&& class_exists( '\WPEverest\URM\FixedPeriodMemebership\FixedPeriodSubscriptionService' )
&& 'paid' === $membership_type
&& ur_string_to_bool( get_user_meta( $membership['user_id'], 'expiration_date_renewal', true ) )
&& ! empty( $membership['expiry_date'] ) ) {
$can_renew = true;
}

$date_to_renew = '';

if ( 'subscription' == $membership_type ) {
Expand Down Expand Up @@ -174,7 +185,20 @@
if ( isset( $membership['status'] ) && in_array( $membership['status'], array( 'canceled', 'expired' ) ) ) {
echo esc_html__( 'N/A', 'user-registration' );
} else {
echo ! empty( $membership['next_billing_date'] ) && strtotime( $membership['next_billing_date'] ) > 0 ? esc_html( date_i18n( get_option( 'date_format' ), strtotime( $membership['next_billing_date'] ) ) ) : __( 'N/A', 'user-registration' );
$next_billing = $membership['next_billing_date'] ?? '';

// For fixed-period paid memberships with annual renewal, use expiration_date user meta.
if ( 'paid' === $membership_type
&& ur_string_to_bool( get_user_meta( $membership['user_id'], 'expiration_date_renewal', true ) ) ) {
$fixed_expiry = get_user_meta( $membership['user_id'], 'expiration_date', true );
if ( ! empty( $fixed_expiry ) ) {
$next_billing = $fixed_expiry;
}
}

echo ! empty( $next_billing ) && strtotime( $next_billing ) > 0
? esc_html( date_i18n( get_option( 'date_format' ), strtotime( $next_billing ) ) )
: esc_html__( 'N/A', 'user-registration' );
}
?>
</td>
Expand Down
Loading