Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
ideadude committed Nov 18, 2021
2 parents dbf1694 + bd4e8ef commit 4fff3a9
Show file tree
Hide file tree
Showing 65 changed files with 642 additions and 114 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
== Changelog ==
= 2.6.6 - 2021-11-18 =
* SECURITY: Updated escaping on the discount codes page in the dashboard to prevent XSS attacks. #1867 (Thanks, Erwan from WPScan)
* BUG FIX/ENHANCEMENT: Added code to remove duplicate active rows in the pmpro_memberships_users table after level change. This might have happened e.g. if users were purchasing a level via the WooCommerce Add On multiple times. #1860 (@dlparker1005)
* BUG FIX/ENHANCEMENT: Improved the REST API endpoints to better support Zapier native requirements. #1862 (@andrewlimaza)
* BUG FIX: Fixed PHP notices in the name parser library. #1861 (@sc0ttkclark)

= 2.6.5 - 2021-11-12 =
* ENHANCEMENT: Introduced new action `pmpro_before_commit_express_checkout` to allow additional changes after an order has been saved but before sending customer to PayPal Express checkout. #1852 (@mircobabini)
* BUG FIX/ENHANCEMENT: Added login compatibility for Jetpack WordPress.com SSO when using the PMPro login page. #1848 (@sc0ttkclark)
Expand Down
44 changes: 22 additions & 22 deletions adminpages/discountcodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -438,18 +438,18 @@
}
?>
<form action="" method="post">
<input name="saveid" type="hidden" value="<?php echo $edit?>" />
<input name="saveid" type="hidden" value="<?php echo esc_attr( $edit ); ?>" />
<?php wp_nonce_field('save', 'pmpro_discountcodes_nonce');?>
<table class="form-table">
<tbody>
<tr>
<th scope="row" valign="top"><label><?php _e('ID', 'paid-memberships-pro' );?>:</label></th>
<td><p class="description"><?php if(!empty($code->id)) echo $code->id; else echo __("This will be generated when you save.", 'paid-memberships-pro' );?></p></td>
<td><p class="description"><?php if(!empty($code->id)) echo esc_html( $code->id ); else echo __("This will be generated when you save.", 'paid-memberships-pro' );?></p></td>
</tr>

<tr>
<th scope="row" valign="top"><label for="code"><?php _e('Code', 'paid-memberships-pro' );?>:</label></th>
<td><input name="code" type="text" size="20" value="<?php echo str_replace("\"", "&quot;", stripslashes($code->code))?>" /></td>
<td><input name="code" type="text" size="20" value="<?php echo esc_attr( $code->code ); ?>" /></td>
</tr>

<?php
Expand Down Expand Up @@ -498,8 +498,8 @@
}
?>
</select>
<input name="starts_day" type="text" size="2" value="<?php echo $selected_starts_day?>" />
<input name="starts_year" type="text" size="4" value="<?php echo $selected_starts_year?>" />
<input name="starts_day" type="text" size="2" value="<?php echo esc_attr( $selected_starts_day ); ?>" />
<input name="starts_year" type="text" size="4" value="<?php echo esc_attr( $selected_starts_year ); ?>" />
</td>
</tr>

Expand All @@ -516,15 +516,15 @@
}
?>
</select>
<input name="expires_day" type="text" size="2" value="<?php echo $selected_expires_day?>" />
<input name="expires_year" type="text" size="4" value="<?php echo $selected_expires_year?>" />
<input name="expires_day" type="text" size="2" value="<?php echo esc_attr( $selected_expires_day ); ?>" />
<input name="expires_year" type="text" size="4" value="<?php echo esc_attr( $selected_expires_year ); ?>" />
</td>
</tr>

<tr>
<th scope="row" valign="top"><label for="uses"><?php _e('Uses', 'paid-memberships-pro' );?>:</label></th>
<td>
<input name="uses" type="text" size="10" value="<?php if(!empty($code->uses)) echo str_replace("\"", "&quot;", stripslashes($code->uses));?>" />
<input name="uses" type="text" size="10" value="<?php if ( ! empty( $code->uses ) ) echo esc_attr( $code->uses ); ?>" />
<p class="description"><?php _e('Leave blank for unlimited uses.', 'paid-memberships-pro' );?></p>
</td>
</tr>
Expand Down Expand Up @@ -566,10 +566,10 @@
$level_checked = false;
?>
<div class="pmpro_discount_level <?php if ( ! pmpro_check_discount_code_level_for_gateway_compatibility( $level ) ) { ?>pmpro_error<?php } ?>">
<input type="hidden" name="all_levels[]" value="<?php echo $level->id?>" />
<input type="checkbox" id="levels_<?php echo $level->id;?>" name="levels[]" value="<?php echo $level->id?>" <?php if(!empty($level->checked)) { ?>checked="checked"<?php } ?> onclick="if(jQuery(this).is(':checked')) jQuery(this).next().next().show(); else jQuery(this).next().next().hide();" />
<label for="levels_<?php echo $level->id;?>"><?php echo $level->name?></label>
<div class="pmpro_discount_levels_pricing level_<?php echo $level->id?>" <?php if(empty($level->checked)) { ?>style="display: none;"<?php } ?>>
<input type="hidden" name="all_levels[]" value="<?php echo esc_attr( $level->id ); ?>" />
<input type="checkbox" id="levels_<?php echo esc_attr( $level->id ); ?>" name="levels[]" value="<?php echo esc_attr( $level->id ); ?>" <?php if(!empty($level->checked)) { ?>checked="checked"<?php } ?> onclick="if(jQuery(this).is(':checked')) jQuery(this).next().next().show(); else jQuery(this).next().next().hide();" />
<label for="levels_<?php echo esc_attr( $level->id ); ?>"><?php echo $level->name?></label>
<div class="pmpro_discount_levels_pricing level_<?php echo esc_attr( $level->id ); ?>" <?php if(empty($level->checked)) { ?>style="display: none;"<?php } ?>>
<table class="form-table">
<tbody>
<tr>
Expand All @@ -590,7 +590,7 @@

<tr>
<th scope="row" valign="top"><label><?php _e('Recurring Subscription', 'paid-memberships-pro' );?>:</label></th>
<td><input class="recurring_checkbox" id="recurring_<?php echo $level->id;?>" name="recurring[]" type="checkbox" value="<?php echo $level->id?>" <?php if(pmpro_isLevelRecurring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).prop('checked')) { jQuery(this).parent().parent().siblings('.recurring_info').show(); if(!jQuery('#custom_trial_<?php echo $level->id?>').is(':checked')) jQuery(this).parent().parent().siblings('.trial_info').hide();} else jQuery(this).parent().parent().siblings('.recurring_info').hide();" /> <label for="recurring_<?php echo $level->id;?>"><?php _e('Check if this level has a recurring subscription payment.', 'paid-memberships-pro' );?></label></td>
<td><input class="recurring_checkbox" id="recurring_<?php echo esc_attr( $level->id );?>" name="recurring[]" type="checkbox" value="<?php echo esc_attr( $level->id ); ?>" <?php if(pmpro_isLevelRecurring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).prop('checked')) { jQuery(this).parent().parent().siblings('.recurring_info').show(); if(!jQuery('#custom_trial_<?php echo esc_attr( $level->id ); ?>').is(':checked')) jQuery(this).parent().parent().siblings('.trial_info').hide();} else jQuery(this).parent().parent().siblings('.recurring_info').hide();" /> <label for="recurring_<?php echo esc_attr( $level->id ); ?>"><?php _e('Check if this level has a recurring subscription payment.', 'paid-memberships-pro' );?></label></td>
</tr>

<tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
Expand All @@ -606,7 +606,7 @@
echo $pmpro_currency_symbol;
?>
<?php _e('per', 'paid-memberships-pro' ); ?>
<input name="cycle_number[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->cycle_number))?>" />
<input name="cycle_number[]" type="text" size="10" value="<?php echo esc_attr( $level->cycle_number ); ?>" />
<select name="cycle_period[]">
<?php
$cycles = array( __('Day(s)', 'paid-memberships-pro' ) => 'Day', __('Week(s)', 'paid-memberships-pro' ) => 'Week', __('Month(s)', 'paid-memberships-pro' ) => 'Month', __('Year(s)', 'paid-memberships-pro' ) => 'Year' );
Expand All @@ -629,7 +629,7 @@
<tr class="recurring_info" <?php if(!pmpro_isLevelRecurring($level)) {?>style="display: none;"<?php } ?>>
<th scope="row" valign="top"><label for="billing_limit"><?php _e('Billing Cycle Limit', 'paid-memberships-pro' );?>:</label></th>
<td>
<input name="billing_limit[]" type="text" size="20" value="<?php echo $level->billing_limit?>" />
<input name="billing_limit[]" type="text" size="20" value="<?php echo esc_attr( $level->billing_limit ); ?>" />
<p class="description">
<?php _e('The <strong>total</strong> number of recurring billing cycles for this level, including the trial period (if applicable) but not including the initial payment. Set to zero if membership is indefinite.', 'paid-memberships-pro' );?>
<?php if ( ( $gateway == "stripe" ) && ! function_exists( 'pmprosbl_plugin_row_meta' ) ) { ?>
Expand All @@ -652,7 +652,7 @@
<tr class="recurring_info" <?php if (!pmpro_isLevelRecurring($level)) echo "style='display:none;'";?>>
<th scope="row" valign="top"><label><?php _e('Custom Trial', 'paid-memberships-pro' );?>:</label></th>
<td>
<input id="custom_trial_<?php echo $level->id?>" id="custom_trial_<?php echo $level->id;?>" name="custom_trial[]" type="checkbox" value="<?php echo $level->id?>" <?php if ( pmpro_isLevelTrial($level) ) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).prop('checked')) jQuery(this).parent().parent().siblings('.trial_info').show(); else jQuery(this).parent().parent().siblings('.trial_info').hide();" /> <label for="custom_trial_<?php echo $level->id;?>"><?php _e('Check to add a custom trial period.', 'paid-memberships-pro' );?></label>
<input id="custom_trial_<?php echo esc_attr( $level->id ); ?>" id="custom_trial_<?php echo esc_attr( $level->id ); ?>" name="custom_trial[]" type="checkbox" value="<?php echo esc_attr( $level->id ); ?>" <?php if ( pmpro_isLevelTrial($level) ) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).prop('checked')) jQuery(this).parent().parent().siblings('.trial_info').show(); else jQuery(this).parent().parent().siblings('.trial_info').hide();" /> <label for="custom_trial_<?php echo esc_attr( $level->id );?>"><?php _e('Check to add a custom trial period.', 'paid-memberships-pro' );?></label>
<?php if($gateway == "twocheckout") { ?>
<p class="description"><strong <?php if(!empty($pmpro_twocheckout_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('2Checkout integration does not support custom trials. You can do one period trials by setting an initial payment different from the billing amount.', 'paid-memberships-pro' );?></strong></p>
<?php } ?>
Expand All @@ -672,7 +672,7 @@
echo $pmpro_currency_symbol;
?>
<?php _e('for the first', 'paid-memberships-pro' );?>
<input name="trial_limit[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->trial_limit))?>" />
<input name="trial_limit[]" type="text" size="10" value="<?php echo esc_attr( $level->trial_limit ); ?>" />
<?php _e('subscription payments', 'paid-memberships-pro' );?>.
<?php if($gateway == "stripe") { ?>
<p class="description"><strong <?php if(!empty($pmpro_stripe_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Stripe integration currently does not support trial amounts greater than $0.', 'paid-memberships-pro' );?></strong></p>
Expand All @@ -686,13 +686,13 @@

<tr>
<th scope="row" valign="top"><label><?php _e('Membership Expiration', 'paid-memberships-pro' );?>:</label></th>
<td><input id="expiration_<?php echo $level->id;?>" name="expiration[]" type="checkbox" value="<?php echo $level->id?>" <?php if(pmpro_isLevelExpiring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).is(':checked')) { jQuery(this).parent().parent().siblings('.expiration_info').show(); } else { jQuery(this).parent().parent().siblings('.expiration_info').hide();}" /> <label for="expiration_<?php echo $level->id;?>"><?php _e('Check this to set when membership access expires.', 'paid-memberships-pro' );?></label></td>
<td><input id="expiration_<?php echo esc_attr( $level->id ); ?>" name="expiration[]" type="checkbox" value="<?php echo esc_attr( $level->id ); ?>" <?php if(pmpro_isLevelExpiring($level)) { echo "checked='checked'"; } ?> onclick="if(jQuery(this).is(':checked')) { jQuery(this).parent().parent().siblings('.expiration_info').show(); } else { jQuery(this).parent().parent().siblings('.expiration_info').hide();}" /> <label for="expiration_<?php echo esc_attr( $level->id ); ?>"><?php _e('Check this to set when membership access expires.', 'paid-memberships-pro' );?></label></td>
</tr>

<tr class="expiration_info" <?php if(!pmpro_isLevelExpiring($level)) {?>style="display: none;"<?php } ?>>
<th scope="row" valign="top"><label for="billing_amount"><?php _e('Expires In', 'paid-memberships-pro' );?>:</label></th>
<td>
<input id="expiration_number" name="expiration_number[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->expiration_number))?>" />
<input id="expiration_number" name="expiration_number[]" type="text" size="10" value="<?php echo esc_attr( $level->expiration_number ); ?>" />
<select id="expiration_period" name="expiration_period[]">
<?php

Expand Down Expand Up @@ -772,8 +772,8 @@
<p class="search-box">
<label class="screen-reader-text" for="post-search-input"><?php _e('Search Discount Codes', 'paid-memberships-pro' );?>:</label>
<input type="hidden" name="page" value="pmpro-discountcodes" />
<input id="post-search-input" type="text" value="<?php if(!empty($s)) echo $s;?>" name="s" size="30" />
<input class="button" type="submit" value="<?php _e('Search', 'paid-memberships-pro' );?>" id="search-submit "/>
<input id="post-search-input" type="text" value="<?php echo esc_attr( wp_unslash( $s ) ); ?>" name="s" size="30" />
<input class="button" type="submit" value="<?php esc_attr_e('Search', 'paid-memberships-pro' );?>" id="search-submit "/>
</p>
</form>

Expand Down Expand Up @@ -806,7 +806,7 @@
<tr<?php if ( ! pmpro_check_discount_code_for_gateway_compatibility( $code->id ) ) { ?> class="pmpro_error"<?php } ?>>
<td><?php echo $code->id?></td>
<td class="has-row-actions">
<a title="<?php echo sprintf( __( 'Edit Code: %s', 'paid-memberships-pro' ), $code->code ); ?>" href="<?php echo add_query_arg( array( 'page' => 'pmpro-discountcodes', 'edit' => $code->id ), admin_url('admin.php' ) ); ?>"><?php echo $code->code?></a>
<a title="<?php echo esc_attr( sprintf( __( 'Edit Code: %s', 'paid-memberships-pro' ), $code->code ) ); ?>" href="<?php echo esc_url( add_query_arg( array( 'page' => 'pmpro-discountcodes', 'edit' => $code->id ), admin_url('admin.php' ) ) ); ?>"><?php echo $code->code?></a>
<div class="row-actions">
<?php
$delete_text = esc_html(
Expand Down
2 changes: 1 addition & 1 deletion adminpages/orders.php
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ function pmpro_ShowMonthOrYear() {
<p class="search-box">
<label class="hidden" for="post-search-input"><?php esc_html_e( 'Search Orders', 'paid-memberships-pro' ); ?>:</label>
<input type="hidden" name="page" value="pmpro-orders"/>
<input id="post-search-input" type="text" value="<?php echo esc_attr( $s ); ?>" name="s"/>
<input id="post-search-input" type="text" value="<?php echo esc_attr( wp_unslash( $s ) ); ?>" name="s"/>
<input class="button" type="submit" value="<?php esc_attr_e( 'Search Orders', 'paid-memberships-pro' ); ?>"/>
</p>

Expand Down
42 changes: 42 additions & 0 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,37 @@ function pmpro_changeMembershipLevel( $level, $user_id = null, $old_level_status
$pmpro_error = sprintf( __( 'Error interacting with database: %s', 'paid-memberships-pro' ), ( ! empty( $wpdb->last_error ) ? $wpdb->last_error : 'unavailable' ) );
return false;
}

/**
* Allow filtering whether to remove duplicate "active" memberships by setting them to "changed".
*
* @since 2.6.6
*
* @param bool $remove_duplicate_memberships Whether to remove duplicate "active" memberships by setting them to "changed".
*/
$remove_duplicate_memberships = apply_filters( 'pmpro_remove_duplicate_membership_entries', true );

if ( $remove_duplicate_memberships ) {
$wpdb->query(
$wpdb->prepare(
"
UPDATE {$wpdb->pmpro_memberships_users}
SET status = %s,
enddate = %s
WHERE user_id = %d
AND membership_id = %d
AND status = %s
AND id != %d
",
'changed',
current_time( 'mysql' ),
$user_id,
$level_id,
'active',
$wpdb->insert_id // Ignore the membership that we just added.
)
);
}
}

// remove cached level
Expand Down Expand Up @@ -3832,3 +3863,14 @@ function pmpro_send_200_http_response() {
ob_flush();
flush();
}

/**
* Returns formatted ISO-8601 date (Used for Zapier Native app.)
* @since 2.6.6
* @param $date date A valid date value.
* @return string The date in ISO-8601 format.
*/
function pmpro_format_date_iso8601( $date ) {
$datetime = new DateTime( $date );
return $datetime->format( DateTime::ATOM );
}
37 changes: 28 additions & 9 deletions includes/lib/name-parser.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/*
Taken from: http://code.google.com/p/php-name-parser/
Changed function names to avoid conflicts.
*/

Expand All @@ -14,11 +14,20 @@
if(!function_exists("pnp_split_full_name"))
{
function pnp_split_full_name($full_name) {
if(empty($full_name))
return "";

$name = [
'salutation' => '',
'fname' => '',
'initials' => '',
'lname' => '',
'suffix' => '',
];

if ( empty( $full_name ) ) {
return $name;
}

$fname = $lname = $initials = NULL;

$full_name = trim($full_name);
// split into words
$unfiltered_name_parts = explode(" ",$full_name);
Expand All @@ -28,11 +37,21 @@ function pnp_split_full_name($full_name) {
if (!empty($word) && $word[0] != "(")
$name_parts[] = $word;
}

if ( empty( $name_parts ) ) {
return $name;
}

$num_words = sizeof($name_parts);

// is the first word a title? (Mr. Mrs, etc)
$salutation = pnp_is_salutation($name_parts[0]);
$suffix = pnp_is_suffix($name_parts[sizeof($name_parts)-1]);

$suffix = false;

if ( isset( $name_parts[sizeof($name_parts)-1] ) ) {
$suffix = pnp_is_suffix( $name_parts[ sizeof( $name_parts ) - 1 ] );
}

// set the range for the middle part of the name (trim prefixes & suffixes)
$start = ($salutation) ? 1 : 0;
Expand All @@ -48,12 +67,12 @@ function pnp_split_full_name($full_name) {
// is it a middle initial or part of their first name?
// if we start off with an initial, we'll call it the first name
if (pnp_is_initial($word)) {
// is the initial the first word?
// is the initial the first word?
if ($i == $start) {
// if so, do a look-ahead to see if they go by their middle name
// for ex: "R. Jason Smith" => "Jason Smith" & "R." is stored as an initial
// but "R. J. Smith" => "R. Smith" and "J." is stored as an initial
if (pnp_is_initial($name_parts[$i+1]))
if ( isset( $name_parts[ $i + 1 ] ) && pnp_is_initial( $name_parts[ $i + 1 ] ) )
$fname .= " ".strtoupper($word);
else
$initials .= " ".strtoupper($word);
Expand All @@ -63,7 +82,7 @@ function pnp_split_full_name($full_name) {
}
} else {
$fname .= " ".pnp_fix_case($word);
}
}
}

// check that we have more than 1 word in our string
Expand Down
Loading

0 comments on commit 4fff3a9

Please sign in to comment.