Paid Memberships Pro - Version 2.4.3

Version Description

  • 2020-08-25
  • SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)
  • SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.
  • BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.
Download this release

Release Info

Developer strangerstudios
Plugin Icon 128x128 Paid Memberships Pro
Version 2.4.3
Comparing to
See all releases

Code changes from version 2.4.1 to 2.4.3

CHANGELOG.txt CHANGED
@@ -1,4 +1,24 @@
1
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  = 2.4.1 - 2020-08-10 =
3
  * BUG FIX: Fixed issues with password resets on WP Engine hosting due to security features added by their mu-plugin.
4
  * BUG FIX: Fixed issue where end dates were showing up incorrectly in the confirmation email sometimes.
1
  == Changelog ==
2
+ = 2.4.3 - 2020-08-25
3
+ * SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)
4
+ * SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.
5
+ * BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.
6
+
7
+ = 2.4.2 - 2020-08-24
8
+ * SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro_edit_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro_rest_api_route_capabilities filter and/or pmpro_rest_api_permissions filter to change this behavior.
9
+ * BUG FIX: Fixed issues with the PMPro REST API endpoints, including the discount code and checkout level endpoints.
10
+ * BUG FIX: Fixed issue with backslashes in the display name when editing form the PMPro frontend profile page.
11
+ * BUG FIX: Fixed issue where timestamps were showing up incorrectly for recent orders shown on the dashboard page.
12
+ BUG FIX: Fixed issue where PMPro would always try to add capabilities to the administrator role, even if you removed that role for some reason.
13
+ * ENHANCEMENT: Added a pmpro_get_no_access_message() function, which can be used to show the no access messages.
14
+ * ENHANCEMENT: Added a "show_noaccess" property to the membership shortcode. When set, it will show the noaccess message to users who don't have the levels specified.
15
+ * ENHANCEMENT: Added a pmpro_user_profile_update_errors hook, which can be used to show errors on the PMPro frontend profile page.
16
+ * ENHANCEMENT: The pmpro_set_capabilities_for_role() function now returns true or false if the caps were added in case others want to use this function and tell if it worked.
17
+ * ENHANCEMENT: You can now include links in the description of the fields you add to the PMPro advanced settings page via the pmpro_custom_advanced_settings filter.
18
+ * ENHANCEMENT: Updated the PayPal gateways to use the latest versions of the PayPal buttons.
19
+ * ENHANCEMENT: Fixed styling of the PMPro update script notice.
20
+ * ENHANCEMENT: Added the pmpro_account_membership_expiration_text filter to the expiration dates shown on the cancel page when using MMPU.
21
+
22
  = 2.4.1 - 2020-08-10 =
23
  * BUG FIX: Fixed issues with password resets on WP Engine hosting due to security features added by their mu-plugin.
24
  * BUG FIX: Fixed issue where end dates were showing up incorrectly in the confirmation email sometimes.
adminpages/admin_header.php CHANGED
@@ -124,6 +124,23 @@
124
  $msgt .= " <a href=\"" . admin_url('admin.php?page=pmpro-membershiplevels') . "\">" . __("Please edit your levels", 'paid-memberships-pro' ) . "</a>.";
125
  }
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  //check gateway dependencies
128
  $gateway = pmpro_getOption('gateway');
129
  if($gateway == "stripe" && version_compare( PHP_VERSION, '5.3.29', '>=' ) ) {
124
  $msgt .= " <a href=\"" . admin_url('admin.php?page=pmpro-membershiplevels') . "\">" . __("Please edit your levels", 'paid-memberships-pro' ) . "</a>.";
125
  }
126
 
127
+ if ( ! pmpro_check_discount_code_for_gateway_compatibility() ) {
128
+ $msg = -1;
129
+ $msgt = __( 'The billing details for some of your discount codes are not supported by your gateway.', 'paid-memberships-pro' );
130
+ if ( $view == 'pmpro-discountcodes' && ! empty($_REQUEST['edit']) && $_REQUEST['edit'] > 0 ) {
131
+ if ( ! pmpro_check_discount_code_for_gateway_compatibility( $_REQUEST['edit'] ) ) {
132
+ $msg = -1;
133
+ $msgt = __( 'The billing details for this discount code are not supported by your gateway.', 'paid-memberships-pro' );
134
+ }
135
+ } elseif ( $view == 'pmpro-discountcodes' ) {
136
+ $msg = -1;
137
+ $msgt .= " " . __("The discount codes with issues are highlighted below.", 'paid-memberships-pro' );
138
+ } else {
139
+ $msgt .= " <a href=\"" . admin_url('admin.php?page=pmpro-discountcodes') . "\">" . __("Please edit your discount codes", 'paid-memberships-pro' ) . "</a>.";
140
+
141
+ }
142
+ }
143
+
144
  //check gateway dependencies
145
  $gateway = pmpro_getOption('gateway');
146
  if($gateway == "stripe" && version_compare( PHP_VERSION, '5.3.29', '>=' ) ) {
adminpages/advancedsettings.php CHANGED
@@ -450,12 +450,17 @@ if ( function_exists( 'pmpro_displayAds' ) && pmpro_displayAds() ) {
450
  default:
451
  break;
452
  }
453
- if (!empty($field['description'])) {
454
- ?>
455
- <p class="description"><?php echo esc_textarea( $field['description'] ); ?></p>
456
- <?php
457
- }
458
- ?>
 
 
 
 
 
459
  </td>
460
  </tr>
461
  <?php
450
  default:
451
  break;
452
  }
453
+ if ( ! empty( $field['description'] ) ) {
454
+ $allowed_pmpro_custom_advanced_settings_html = array (
455
+ 'a' => array (
456
+ 'href' => array(),
457
+ 'target' => array(),
458
+ 'title' => array(),
459
+ ),
460
+ );
461
+ ?>
462
+ <p class="description"><?php echo wp_kses( $field['description'], $allowed_pmpro_custom_advanced_settings_html ); ?></p>
463
+ <?php } ?>
464
  </td>
465
  </tr>
466
  <?php
adminpages/dashboard.php CHANGED
@@ -343,7 +343,7 @@ function pmpro_dashboard_report_recent_orders_callback() {
343
  echo '<br />(' . $order->status . ')';
344
  } ?>
345
  </td>
346
- <td><?php echo date_i18n( get_option( 'date_format' ), $order->timestamp ); ?></td>
347
  </tr>
348
  <?php
349
  }
343
  echo '<br />(' . $order->status . ')';
344
  } ?>
345
  </td>
346
+ <td><?php echo date_i18n( get_option( 'date_format' ), $order->getTimestamp() ); ?></td>
347
  </tr>
348
  <?php
349
  }
adminpages/discountcodes.php CHANGED
@@ -6,7 +6,7 @@
6
  }
7
 
8
  //vars
9
- global $wpdb, $pmpro_currency_symbol;
10
 
11
  $now = current_time( 'timestamp' );
12
 
@@ -562,7 +562,7 @@
562
  else
563
  $level_checked = false;
564
  ?>
565
- <div class="pmpro_discount_level">
566
  <input type="hidden" name="all_levels[]" value="<?php echo $level->id?>" />
567
  <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();" />
568
  <label for="levels_<?php echo $level->id;?>"><?php echo $level->name?></label>
@@ -615,6 +615,9 @@
615
  ?>
616
  </select>
617
  <p class="description"><?php _e('The amount to be billed one cycle after the initial payment.', 'paid-memberships-pro' );?></p>
 
 
 
618
  </td>
619
  </tr>
620
 
@@ -622,13 +625,33 @@
622
  <th scope="row" valign="top"><label for="billing_limit"><?php _e('Billing Cycle Limit', 'paid-memberships-pro' );?>:</label></th>
623
  <td>
624
  <input name="billing_limit[]" type="text" size="20" value="<?php echo $level->billing_limit?>" />
625
- <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' );?></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
626
  </td>
627
  </tr>
628
 
629
  <tr class="recurring_info" <?php if (!pmpro_isLevelRecurring($level)) echo "style='display:none;'";?>>
630
  <th scope="row" valign="top"><label><?php _e('Custom Trial', 'paid-memberships-pro' );?>:</label></th>
631
- <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></td>
 
 
 
 
 
632
  </tr>
633
 
634
  <tr class="trial_info recurring_info" <?php if (!pmpro_isLevelTrial($level)) echo "style='display:none;'";?>>
@@ -646,6 +669,13 @@
646
  <?php _e('for the first', 'paid-memberships-pro' );?>
647
  <input name="trial_limit[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->trial_limit))?>" />
648
  <?php _e('subscription payments', 'paid-memberships-pro' );?>.
 
 
 
 
 
 
 
649
  </td>
650
  </tr>
651
 
@@ -667,6 +697,7 @@
667
  echo ">$name</option>";
668
  }
669
  ?>
 
670
  </select>
671
  <p class="description"><?php _e('Set the duration of membership access. Note that the any future payments (recurring subscription, if any) will be cancelled when the membership expires.', 'paid-memberships-pro' );?></p>
672
  </td>
@@ -755,18 +786,17 @@
755
  </thead>
756
  <tbody>
757
  <?php if ( !empty( $s ) && empty( $codes ) ) { ?>
758
- <tr class="alternate">
759
  <td colspan="6">
760
  <?php echo esc_attr_e( 'Code not found.', 'paid-memberships-pro' ); ?>
761
  </td>
762
  </tr>
763
  <?php } ?>
764
  <?php
765
- $count = 0;
766
  foreach($codes as $code) {
767
  $uses = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = %d", $code->id ) );
768
  ?>
769
- <tr<?php if($count++ % 2 == 1) { ?> class="alternate"<?php } ?>>
770
  <td><?php echo $code->id?></td>
771
  <td class="has-row-actions">
772
  <a title="<?php echo sprintf( 'Edit Code: %s', $code->code ); ?>" href="<?php echo add_query_arg( array( 'page' => 'pmpro-discountcodes', 'edit' => $code->id ), admin_url('admin.php' ) ); ?>"><?php echo $code->code?></a>
6
  }
7
 
8
  //vars
9
+ global $wpdb, $pmpro_currency_symbol, $pmpro_stripe_error, $pmpro_braintree_error, $pmpro_payflow_error, $pmpro_twocheckout_error;
10
 
11
  $now = current_time( 'timestamp' );
12
 
562
  else
563
  $level_checked = false;
564
  ?>
565
+ <div class="pmpro_discount_level <?php if ( ! pmpro_check_discount_code_level_for_gateway_compatibility( $level ) ) { ?>pmpro_error<?php } ?>">
566
  <input type="hidden" name="all_levels[]" value="<?php echo $level->id?>" />
567
  <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();" />
568
  <label for="levels_<?php echo $level->id;?>"><?php echo $level->name?></label>
615
  ?>
616
  </select>
617
  <p class="description"><?php _e('The amount to be billed one cycle after the initial payment.', 'paid-memberships-pro' );?></p>
618
+ <?php if($gateway == "braintree") { ?>
619
+ <strong <?php if(!empty($pmpro_braintree_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Braintree integration currently only supports billing periods of "Month" or "Year".', 'paid-memberships-pro' );?></strong>
620
+ <?php } ?>
621
  </td>
622
  </tr>
623
 
625
  <th scope="row" valign="top"><label for="billing_limit"><?php _e('Billing Cycle Limit', 'paid-memberships-pro' );?>:</label></th>
626
  <td>
627
  <input name="billing_limit[]" type="text" size="20" value="<?php echo $level->billing_limit?>" />
628
+ <p class="description">
629
+ <?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' );?>
630
+ <?php if ( ( $gateway == "stripe" ) && ! function_exists( 'pmprosbl_plugin_row_meta' ) ) { ?>
631
+ <br /><strong <?php if(!empty($pmpro_stripe_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Stripe integration currently does not support billing limits. You can still set an expiration date below.', 'paid-memberships-pro' );?></strong>
632
+ <?php if ( ! function_exists( 'pmprosd_pmpro_membership_level_after_other_settings' ) ) {
633
+ $allowed_sbl_html = array (
634
+ 'a' => array (
635
+ 'href' => array(),
636
+ 'target' => array(),
637
+ 'title' => array(),
638
+ ),
639
+ );
640
+ echo '<br />' . sprintf( wp_kses( __( 'Optional: Allow billing limits with Stripe using the <a href="%s" title="Paid Memberships Pro - Stripe Billing Limits Add On" target="_blank">Stripe Billing Limits Add On</a>.', 'paid-memberships-pro' ), $allowed_sbl_html ), 'https://www.paidmembershipspro.com/add-ons/pmpro-stripe-billing-limits/?utm_source=plugin&utm_medium=pmpro-membershiplevels&utm_campaign=add-ons&utm_content=stripe-billing-limits' ) . '</em></td></tr>';
641
+ } ?>
642
+ <?php } ?>
643
+ </p>
644
  </td>
645
  </tr>
646
 
647
  <tr class="recurring_info" <?php if (!pmpro_isLevelRecurring($level)) echo "style='display:none;'";?>>
648
  <th scope="row" valign="top"><label><?php _e('Custom Trial', 'paid-memberships-pro' );?>:</label></th>
649
+ <td>
650
+ <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>
651
+ <?php if($gateway == "twocheckout") { ?>
652
+ <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>
653
+ <?php } ?>
654
+ </td>
655
  </tr>
656
 
657
  <tr class="trial_info recurring_info" <?php if (!pmpro_isLevelTrial($level)) echo "style='display:none;'";?>>
669
  <?php _e('for the first', 'paid-memberships-pro' );?>
670
  <input name="trial_limit[]" type="text" size="10" value="<?php echo str_replace("\"", "&quot;", stripslashes($level->trial_limit))?>" />
671
  <?php _e('subscription payments', 'paid-memberships-pro' );?>.
672
+ <?php if($gateway == "stripe") { ?>
673
+ <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>
674
+ <?php } elseif($gateway == "braintree") { ?>
675
+ <p class="description"><strong <?php if(!empty($pmpro_braintree_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Braintree integration currently does not support trial amounts greater than $0.', 'paid-memberships-pro' );?></strong></p>
676
+ <?php } elseif($gateway == "payflowpro") { ?>
677
+ <p class="description"><strong <?php if(!empty($pmpro_payflow_error)) { ?>class="pmpro_red"<?php } ?>><?php _e('Payflow integration currently does not support trial amounts greater than $0.', 'paid-memberships-pro' );?></strong></p>
678
+ <?php } ?>
679
  </td>
680
  </tr>
681
 
697
  echo ">$name</option>";
698
  }
699
  ?>
700
+
701
  </select>
702
  <p class="description"><?php _e('Set the duration of membership access. Note that the any future payments (recurring subscription, if any) will be cancelled when the membership expires.', 'paid-memberships-pro' );?></p>
703
  </td>
786
  </thead>
787
  <tbody>
788
  <?php if ( !empty( $s ) && empty( $codes ) ) { ?>
789
+ <tr>
790
  <td colspan="6">
791
  <?php echo esc_attr_e( 'Code not found.', 'paid-memberships-pro' ); ?>
792
  </td>
793
  </tr>
794
  <?php } ?>
795
  <?php
 
796
  foreach($codes as $code) {
797
  $uses = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->pmpro_discount_codes_uses WHERE code_id = %d", $code->id ) );
798
  ?>
799
+ <tr<?php if ( ! pmpro_check_discount_code_for_gateway_compatibility( $code->id ) ) { ?> class="pmpro_error"<?php } ?>>
800
  <td><?php echo $code->id?></td>
801
  <td class="has-row-actions">
802
  <a title="<?php echo sprintf( 'Edit Code: %s', $code->code ); ?>" href="<?php echo add_query_arg( array( 'page' => 'pmpro-discountcodes', 'edit' => $code->id ), admin_url('admin.php' ) ); ?>"><?php echo $code->code?></a>
adminpages/functions.php CHANGED
@@ -158,6 +158,109 @@ function pmpro_checkLevelForBraintreeCompatibility($level = NULL)
158
  return true;
159
  }
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  /*
162
  Checks if PMPro settings are complete or if there are any errors.
163
 
158
  return true;
159
  }
160
 
161
+ /**
162
+ * Checks if a discount code's settings are compatible with the active gateway.
163
+ *
164
+ */
165
+ function pmpro_check_discount_code_for_gateway_compatibility( $discount_code = NULL ) {
166
+ // Return if no gateway is set.
167
+ $gateway = pmpro_getOption( 'gateway' );
168
+ if ( empty( $gateway ) ) {
169
+ return true;
170
+ }
171
+
172
+ global $wpdb;
173
+
174
+ // Check ALL the discount codes if none specified.
175
+ if ( empty( $discount_code ) ) {
176
+ $discount_codes = $wpdb->get_results( "SELECT * FROM $wpdb->pmpro_discount_codes" );
177
+ if ( ! empty( $discount_codes ) ) {
178
+ foreach ( $discount_codes as $discount_code ) {
179
+ if ( ! pmpro_check_discount_code_for_gateway_compatibility( $discount_code ) ) {
180
+ return false;
181
+ }
182
+ }
183
+ }
184
+ } else {
185
+ if ( ! is_numeric( $discount_code ) ) {
186
+ // Convert the code array into a single id.
187
+ $discount_code = $discount_code->id;
188
+ }
189
+ // Check ALL the discount code levels for this code.
190
+ $discount_codes_levels = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->pmpro_discount_codes_levels WHERE code_id = %d", $discount_code ) );
191
+ if ( ! empty( $discount_codes_levels ) ) {
192
+ foreach ( $discount_codes_levels as $discount_code_level ) {
193
+ if ( ! pmpro_check_discount_code_level_for_gateway_compatibility( $discount_code_level ) ) {
194
+ return false;
195
+ }
196
+ }
197
+ }
198
+ }
199
+ return true;
200
+ }
201
+
202
+ /**
203
+ * Checks if a discount code's settings are compatible with the active gateway.
204
+ *
205
+ */
206
+ function pmpro_check_discount_code_level_for_gateway_compatibility( $discount_code_level = NULL ) {
207
+ // Return if no gateway is set.
208
+ $gateway = pmpro_getOption( 'gateway' );
209
+ if ( empty( $gateway ) ) {
210
+ return true;
211
+ }
212
+
213
+ global $wpdb;
214
+
215
+ // Check ALL the discount code levels if none specified.
216
+ if ( empty( $discount_code_level ) ) {
217
+ $sqlQuery = "SELECT * FROM $wpdb->pmpro_discount_codes_levels ORDER BY id ASC";
218
+ $discount_codes_levels = $wpdb->get_results($sqlQuery, OBJECT);
219
+ if ( ! empty( $discount_codes_levels ) ) {
220
+ foreach ( $discount_codes_levels as $discount_code_level ) {
221
+ if ( ! pmpro_check_discount_code_level_for_gateway_compatibility( $discount_code_level ) ) {
222
+ return false;
223
+ }
224
+ }
225
+ }
226
+ } else {
227
+ // Need to look it up?
228
+ if ( is_numeric( $discount_code_level ) ) {
229
+ $discount_code_level = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->pmpro_discount_codes_levels WHERE id = %d LIMIT 1" , $discount_code_level ) );
230
+ }
231
+
232
+ // Check this discount code level for gateway compatibility
233
+ if ( $gateway == 'stripe' ) {
234
+ if ( ( $discount_code_level->billing_limit > 0 ) && ! function_exists( 'pmprosbl_plugin_row_meta' ) ) {
235
+ global $pmpro_stripe_error;
236
+ $pmpro_stripe_error = true;
237
+ return false;
238
+ }
239
+ } elseif ( $gateway == 'payflowpro' ) {
240
+ if ( $discount_code_level->trial_amount > 0 ) {
241
+ global $pmpro_payflow_error;
242
+ $pmpro_payflow_error = true;
243
+ return false;
244
+ }
245
+ } elseif ( $gateway == 'braintree' ) {
246
+ if ( $discount_code_level->trial_amount > 0 ||
247
+ ( $discount_code_level->cycle_number > 0 && ( $discount_code_level->cycle_period == "Day" || $discount_code_level->cycle_period == "Week" ) ) ) {
248
+ global $pmpro_braintree_error;
249
+ $pmpro_braintree_error = true;
250
+ return false;
251
+ }
252
+ } if ( $gateway == 'twocheckout' ) {
253
+ if ( $discount_code_level->trial_amount > $discount_code_level->billing_amount ) {
254
+ global $pmpro_twocheckout_error;
255
+ $pmpro_twocheckout_error = true;
256
+ return false;
257
+ }
258
+ }
259
+ }
260
+
261
+ return true;
262
+ }
263
+
264
  /*
265
  Checks if PMPro settings are complete or if there are any errors.
266
 
adminpages/orders-csv.php CHANGED
@@ -498,7 +498,7 @@ for ( $ic = 1; $ic <= $iterations; $ic ++ ) {
498
  }
499
 
500
  //timestamp
501
- $ts = date_i18n( $dateformat, $order->timestamp );
502
  array_push( $csvoutput, pmpro_enclose( $ts ) );
503
 
504
  //any extra columns
498
  }
499
 
500
  //timestamp
501
+ $ts = date_i18n( $dateformat, $order->getTimestamp() );
502
  array_push( $csvoutput, pmpro_enclose( $ts ) );
503
 
504
  //any extra columns
adminpages/orders.php CHANGED
@@ -815,11 +815,11 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
815
  <td>
816
  <?php
817
  if ( in_array( 'timestamp', $read_only_fields ) && $order_id > 0 ) {
818
- echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $order->timestamp ) );
819
  } else {
820
  // set up date vars
821
  if ( ! empty( $order->timestamp ) ) {
822
- $timestamp = $order->timestamp;
823
  } else {
824
  $timestamp = current_time( 'timestamp' );
825
  }
@@ -1452,8 +1452,8 @@ if ( function_exists( 'pmpro_add_email_order_modal' ) ) {
1452
  </td>
1453
  <td><?php echo esc_html( $order->status ); ?></td>
1454
  <td>
1455
- <?php echo esc_html( date_i18n( get_option( 'date_format' ), $order->timestamp ) ); ?><br/>
1456
- <?php echo esc_html( date_i18n( get_option( 'time_format' ), $order->timestamp ) ); ?>
1457
  </td>
1458
  <td>
1459
  <?php if ( $order->getDiscountCode() ) { ?>
815
  <td>
816
  <?php
817
  if ( in_array( 'timestamp', $read_only_fields ) && $order_id > 0 ) {
818
+ echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $order->getTimestamp() ) );
819
  } else {
820
  // set up date vars
821
  if ( ! empty( $order->timestamp ) ) {
822
+ $timestamp = $order->getTimestamp();
823
  } else {
824
  $timestamp = current_time( 'timestamp' );
825
  }
1452
  </td>
1453
  <td><?php echo esc_html( $order->status ); ?></td>
1454
  <td>
1455
+ <?php echo esc_html( date_i18n( get_option( 'date_format' ), $order->getTimestamp() ) ); ?><br/>
1456
+ <?php echo esc_html( date_i18n( get_option( 'time_format' ), $order->getTimestamp() ) ); ?>
1457
  </td>
1458
  <td>
1459
  <?php if ( $order->getDiscountCode() ) { ?>
adminpages/templates/orders-email.php CHANGED
@@ -15,7 +15,7 @@
15
  </tr>
16
  <tr>
17
  <td>
18
- <?php echo __( 'Date:', 'paid-memberships-pro' ) . '&nbsp;' . date_i18n( 'Y-m-d', $order->timestamp ) ?>
19
  </td>
20
  </tr>
21
  <?php if(!empty($order->billing->name)): ?>
15
  </tr>
16
  <tr>
17
  <td>
18
+ <?php echo __( 'Date:', 'paid-memberships-pro' ) . '&nbsp;' . date_i18n( 'Y-m-d', $order->getTimestamp() ) ?>
19
  </td>
20
  </tr>
21
  <?php if(!empty($order->billing->name)): ?>
adminpages/templates/orders-print.php CHANGED
@@ -51,7 +51,7 @@
51
  </tr>
52
  <tr>
53
  <td>
54
- <?php echo __( 'Date:', 'paid-memberships-pro' ) . '&nbsp;' . date_i18n( get_option( 'date_format' ), $order->timestamp ); ?>
55
  </td>
56
  </tr>
57
  </table>
51
  </tr>
52
  <tr>
53
  <td>
54
+ <?php echo __( 'Date:', 'paid-memberships-pro' ) . '&nbsp;' . date_i18n( get_option( 'date_format' ), $order->getTimestamp() ); ?>
55
  </td>
56
  </tr>
57
  </table>
classes/class.memberorder.php CHANGED
@@ -134,16 +134,13 @@
134
  $this->gateway_environment = $dbobj->gateway_environment;
135
  $this->payment_transaction_id = $dbobj->payment_transaction_id;
136
  $this->subscription_transaction_id = $dbobj->subscription_transaction_id;
137
- $this->timestamp = $dbobj->timestamp;
138
  $this->affiliate_id = $dbobj->affiliate_id;
139
  $this->affiliate_subid = $dbobj->affiliate_subid;
140
 
141
  $this->notes = $dbobj->notes;
142
  $this->checkout_id = $dbobj->checkout_id;
143
 
144
- // Fix the timestamp for local time
145
- $this->timestamp = strtotime( get_date_from_gmt( $this->timestamp, 'Y-m-d H:i:s' ) );
146
-
147
  //reset the gateway
148
  if(empty($this->nogateway))
149
  $this->setGateway();
@@ -525,6 +522,16 @@
525
  return $this->tax;
526
  }
527
 
 
 
 
 
 
 
 
 
 
 
528
  /**
529
  * Change the timestamp of an order by passing in year, month, day, time.
530
  *
@@ -545,10 +552,12 @@
545
  global $wpdb;
546
  $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET timestamp = '" . $date . "' WHERE id = '" . $this->id . "' LIMIT 1";
547
 
548
- if($wpdb->query($this->sqlQuery) !== "false")
 
549
  return $this->getMemberOrderByID($this->id);
550
- else
551
  return false;
 
552
  }
553
 
554
  /**
134
  $this->gateway_environment = $dbobj->gateway_environment;
135
  $this->payment_transaction_id = $dbobj->payment_transaction_id;
136
  $this->subscription_transaction_id = $dbobj->subscription_transaction_id;
137
+ $this->timestamp = strtotime( $dbobj->timestamp );
138
  $this->affiliate_id = $dbobj->affiliate_id;
139
  $this->affiliate_subid = $dbobj->affiliate_subid;
140
 
141
  $this->notes = $dbobj->notes;
142
  $this->checkout_id = $dbobj->checkout_id;
143
 
 
 
 
144
  //reset the gateway
145
  if(empty($this->nogateway))
146
  $this->setGateway();
522
  return $this->tax;
523
  }
524
 
525
+ /**
526
+ * Get the timestamp for this order.
527
+ *
528
+ * @param bool $gmt whether to return GMT time or local timestamp.
529
+ * @return int timestamp.
530
+ */
531
+ function getTimestamp( $gmt = false ) {
532
+ return $gmt ? $this->timestamp : strtotime( get_date_from_gmt( date( 'Y-m-d H:i:s', $this->timestamp ) ) );
533
+ }
534
+
535
  /**
536
  * Change the timestamp of an order by passing in year, month, day, time.
537
  *
552
  global $wpdb;
553
  $this->sqlQuery = "UPDATE $wpdb->pmpro_membership_orders SET timestamp = '" . $date . "' WHERE id = '" . $this->id . "' LIMIT 1";
554
 
555
+ if($wpdb->query($this->sqlQuery) !== "false") {
556
+ $this->timestamp = strtotime( $date );
557
  return $this->getMemberOrderByID($this->id);
558
+ } else {
559
  return false;
560
+ }
561
  }
562
 
563
  /**
classes/class.pmproemail.php CHANGED
@@ -288,7 +288,7 @@
288
 
289
  $this->data["invoice_id"] = $invoice->code;
290
  $this->data["invoice_total"] = pmpro_formatPrice($invoice->total);
291
- $this->data["invoice_date"] = date_i18n(get_option('date_format'), $invoice->timestamp);
292
  $this->data["billing_name"] = $invoice->billing->name;
293
  $this->data["billing_street"] = $invoice->billing->street;
294
  $this->data["billing_city"] = $invoice->billing->city;
@@ -388,7 +388,7 @@
388
 
389
  $this->data["invoice_id"] = $invoice->code;
390
  $this->data["invoice_total"] = pmpro_formatPrice($invoice->total);
391
- $this->data["invoice_date"] = date_i18n(get_option('date_format'), $invoice->timestamp);
392
  $this->data["billing_name"] = $invoice->billing->name;
393
  $this->data["billing_street"] = $invoice->billing->street;
394
  $this->data["billing_city"] = $invoice->billing->city;
@@ -711,7 +711,7 @@
711
  "user_email" => $user->user_email,
712
  "invoice_id" => $invoice->code,
713
  "invoice_total" => pmpro_formatPrice($invoice->total),
714
- "invoice_date" => date_i18n(get_option('date_format'), $invoice->timestamp),
715
  "billing_name" => $invoice->billing->name,
716
  "billing_street" => $invoice->billing->street,
717
  "billing_city" => $invoice->billing->city,
288
 
289
  $this->data["invoice_id"] = $invoice->code;
290
  $this->data["invoice_total"] = pmpro_formatPrice($invoice->total);
291
+ $this->data["invoice_date"] = date_i18n( get_option( 'date_format' ), $invoice->getTimestamp() );
292
  $this->data["billing_name"] = $invoice->billing->name;
293
  $this->data["billing_street"] = $invoice->billing->street;
294
  $this->data["billing_city"] = $invoice->billing->city;
388
 
389
  $this->data["invoice_id"] = $invoice->code;
390
  $this->data["invoice_total"] = pmpro_formatPrice($invoice->total);
391
+ $this->data["invoice_date"] = date_i18n(get_option('date_format'), $invoice->getTimestamp());
392
  $this->data["billing_name"] = $invoice->billing->name;
393
  $this->data["billing_street"] = $invoice->billing->street;
394
  $this->data["billing_city"] = $invoice->billing->city;
711
  "user_email" => $user->user_email,
712
  "invoice_id" => $invoice->code,
713
  "invoice_total" => pmpro_formatPrice($invoice->total),
714
+ "invoice_date" => date_i18n(get_option('date_format'), $invoice->getTimestamp()),
715
  "billing_name" => $invoice->billing->name,
716
  "billing_street" => $invoice->billing->street,
717
  "billing_city" => $invoice->billing->city,
classes/gateways/class.pmprogateway_paypal.php CHANGED
@@ -278,7 +278,7 @@
278
  <?php if($gateway == "paypal" || $gateway == "paypalexpress" || $gateway == "paypalstandard") { ?>
279
  <span id="pmpro_paypalexpress_checkout" <?php if(($gateway != "paypalexpress" && $gateway != "paypalstandard") || !$pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
280
  <input type="hidden" name="submit-checkout" value="1" />
281
- <input type="image" id="pmpro_btn-submit-paypal" class="<?php echo pmpro_get_element_class( 'pmpro_btn-submit-checkout' ); ?>" value="<?php _e('Check Out with PayPal', 'paid-memberships-pro' );?> &raquo;" src="<?php echo apply_filters("pmpro_paypal_button_image", "https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif");?>" />
282
  </span>
283
  <?php } ?>
284
 
@@ -762,7 +762,7 @@
762
  /** Initial payment **/
763
  $nvpStr = "";
764
  // STARTDATE is Required, even if useless here. Start from 24h before the order timestamp, to avoid timezone related issues.
765
- $nvpStr .= "&STARTDATE=" . urlencode( gmdate( DATE_W3C, $order->timestamp-DAY_IN_SECONDS ) . 'Z' );
766
  // filter results by a specific transaction id.
767
  $nvpStr .= "&TRANSACTIONID=" . urlencode($order->subscription_transaction_id);
768
 
278
  <?php if($gateway == "paypal" || $gateway == "paypalexpress" || $gateway == "paypalstandard") { ?>
279
  <span id="pmpro_paypalexpress_checkout" <?php if(($gateway != "paypalexpress" && $gateway != "paypalstandard") || !$pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
280
  <input type="hidden" name="submit-checkout" value="1" />
281
+ <input type="image" id="pmpro_btn-submit-paypal" class="<?php echo pmpro_get_element_class( 'pmpro_btn-submit-checkout' ); ?>" value="<?php _e('Check Out with PayPal', 'paid-memberships-pro' );?> &raquo;" src="<?php echo apply_filters("pmpro_paypal_button_image", "https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-medium.png");?>" />
282
  </span>
283
  <?php } ?>
284
 
762
  /** Initial payment **/
763
  $nvpStr = "";
764
  // STARTDATE is Required, even if useless here. Start from 24h before the order timestamp, to avoid timezone related issues.
765
+ $nvpStr .= "&STARTDATE=" . urlencode( gmdate( DATE_W3C, $order->getTimestamp() - DAY_IN_SECONDS ) . 'Z' );
766
  // filter results by a specific transaction id.
767
  $nvpStr .= "&TRANSACTIONID=" . urlencode($order->subscription_transaction_id);
768
 
classes/gateways/class.pmprogateway_paypalexpress.php CHANGED
@@ -473,7 +473,7 @@
473
  ?>
474
  <span id="pmpro_paypalexpress_checkout" <?php if(($gateway != "paypalexpress" && $gateway != "paypalstandard") || !$pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
475
  <input type="hidden" name="submit-checkout" value="1" />
476
- <input type="image" id="pmpro_btn-submit-paypalexpress" class="<?php echo pmpro_get_element_class( 'pmpro_btn-submit-checkout' ); ?>" value="<?php _e('Check Out with PayPal', 'paid-memberships-pro' );?> &raquo;" src="<?php echo apply_filters("pmpro_paypal_button_image", "https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif");?>" />
477
  </span>
478
 
479
  <span id="pmpro_submit_span" <?php if(($gateway == "paypalexpress" || $gateway == "paypalstandard") && $pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
@@ -614,6 +614,7 @@
614
  $order->status = "review";
615
 
616
  //update order
 
617
  $order->saveOrder();
618
 
619
  return true;
@@ -844,7 +845,7 @@
844
  /** Initial payment **/
845
  $nvpStr = "";
846
  // STARTDATE is Required, even if useless here. Start from 24h before the order timestamp, to avoid timezone related issues.
847
- $nvpStr .= "&STARTDATE=" . urlencode( gmdate( DATE_W3C, $order->timestamp-DAY_IN_SECONDS ) . 'Z' );
848
  // filter results by a specific transaction id.
849
  $nvpStr .= "&TRANSACTIONID=" . urlencode($order->subscription_transaction_id);
850
 
473
  ?>
474
  <span id="pmpro_paypalexpress_checkout" <?php if(($gateway != "paypalexpress" && $gateway != "paypalstandard") || !$pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
475
  <input type="hidden" name="submit-checkout" value="1" />
476
+ <input type="image" id="pmpro_btn-submit-paypalexpress" class="<?php echo pmpro_get_element_class( 'pmpro_btn-submit-checkout' ); ?>" value="<?php _e('Check Out with PayPal', 'paid-memberships-pro' );?> &raquo;" src="<?php echo apply_filters("pmpro_paypal_button_image", "https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-medium.png");?>" />
477
  </span>
478
 
479
  <span id="pmpro_submit_span" <?php if(($gateway == "paypalexpress" || $gateway == "paypalstandard") && $pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
614
  $order->status = "review";
615
 
616
  //update order
617
+
618
  $order->saveOrder();
619
 
620
  return true;
845
  /** Initial payment **/
846
  $nvpStr = "";
847
  // STARTDATE is Required, even if useless here. Start from 24h before the order timestamp, to avoid timezone related issues.
848
+ $nvpStr .= "&STARTDATE=" . urlencode( gmdate( DATE_W3C, $order->getTimestamp() - DAY_IN_SECONDS ) . 'Z' );
849
  // filter results by a specific transaction id.
850
  $nvpStr .= "&TRANSACTIONID=" . urlencode($order->subscription_transaction_id);
851
 
classes/gateways/class.pmprogateway_paypalstandard.php CHANGED
@@ -238,7 +238,7 @@
238
  ?>
239
  <span id="pmpro_paypalexpress_checkout" <?php if(($gateway != "paypalexpress" && $gateway != "paypalstandard") || !$pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
240
  <input type="hidden" name="submit-checkout" value="1" />
241
- <input type="image" value="<?php _e('Check Out with PayPal', 'paid-memberships-pro' );?> &raquo;" src="<?php echo apply_filters("pmpro_paypal_button_image", "https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif");?>" />
242
  </span>
243
 
244
  <span id="pmpro_submit_span" <?php if(($gateway == "paypalexpress" || $gateway == "paypalstandard") && $pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
238
  ?>
239
  <span id="pmpro_paypalexpress_checkout" <?php if(($gateway != "paypalexpress" && $gateway != "paypalstandard") || !$pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
240
  <input type="hidden" name="submit-checkout" value="1" />
241
+ <input type="image" value="<?php _e('Check Out with PayPal', 'paid-memberships-pro' );?> &raquo;" src="<?php echo apply_filters("pmpro_paypal_button_image", "https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-medium.png");?>" />
242
  </span>
243
 
244
  <span id="pmpro_submit_span" <?php if(($gateway == "paypalexpress" || $gateway == "paypalstandard") && $pmpro_requirebilling) { ?>style="display: none;"<?php } ?>>
includes/capabilities.php CHANGED
@@ -24,20 +24,23 @@ add_action('admin_init', 'pmpro_check_admin_capabilities', 5, 2);
24
  // use the capability definition for $role_name and add/remove capabilities as requested
25
  function pmpro_set_capabilities_for_role( $role_name, $action = 'enable' )
26
  {
27
- $cap_array = pmpro_get_capability_defs($role_name);
28
-
29
- //add caps to specified role
30
  $role = get_role( $role_name );
 
 
 
 
 
 
31
 
32
  // Iterate through the relevant caps for the role & add or remove them
33
- foreach( $cap_array as $cap_name )
34
- {
35
  if ( $action == 'enable' )
36
- $role->add_cap($cap_name);
37
 
38
  if ( $action == 'disable' )
39
- $role->remove_cap($cap_name);
40
  }
 
41
  }
42
 
43
  // used to define what capabilities goes with what role.
24
  // use the capability definition for $role_name and add/remove capabilities as requested
25
  function pmpro_set_capabilities_for_role( $role_name, $action = 'enable' )
26
  {
 
 
 
27
  $role = get_role( $role_name );
28
+ if ( empty( $role ) ) {
29
+ // Role does not exist.
30
+ return false;
31
+ }
32
+
33
+ $cap_array = pmpro_get_capability_defs( $role_name );
34
 
35
  // Iterate through the relevant caps for the role & add or remove them
36
+ foreach( $cap_array as $cap_name ) {
 
37
  if ( $action == 'enable' )
38
+ $role->add_cap( $cap_name );
39
 
40
  if ( $action == 'disable' )
41
+ $role->remove_cap( $cap_name );
42
  }
43
+ return true;
44
  }
45
 
46
  // used to define what capabilities goes with what role.
includes/content.php CHANGED
@@ -347,45 +347,7 @@ function pmpro_membership_content_filter( $content, $skipcheck = false ) {
347
  $content = "";
348
  }
349
 
350
- if( empty($post_membership_levels_ids ) ) {
351
- $post_membership_levels_ids = array();
352
- }
353
-
354
- if( empty( $post_membership_levels_names ) ) {
355
- $post_membership_levels_names = array();
356
- }
357
-
358
- //hide levels which don't allow signups by default
359
- if( ! apply_filters("pmpro_membership_content_filter_disallowed_levels", false, $post_membership_levels_ids, $post_membership_levels_names ) ) {
360
- foreach($post_membership_levels_ids as $key=>$id) {
361
- //does this level allow registrations?
362
- $level_obj = pmpro_getLevel( $id );
363
- if( empty( $level_obj ) || empty( $level_obj->allow_signups ) ) {
364
- unset( $post_membership_levels_ids[$key] );
365
- unset( $post_membership_levels_names[$key] );
366
- }
367
- }
368
- }
369
-
370
- $pmpro_content_message_pre = '<div class="' . pmpro_get_element_class( 'pmpro_content_message' ) . '">';
371
- $pmpro_content_message_post = '</div>';
372
-
373
- $sr_search = array("!!levels!!", "!!referrer!!", "!!login_url!!", "!!login_page_url!!", "!!levels_url!!", "!!levels_page_url!!");
374
- $sr_replace = array(pmpro_implodeToEnglish($post_membership_levels_names), urlencode(site_url($_SERVER['REQUEST_URI'])), esc_url( pmpro_login_url() ), esc_url( pmpro_login_url() ), esc_url( pmpro_url( 'levels' ) ), esc_url( pmpro_url( 'levels' ) ));
375
-
376
- //get the correct message to show at the bottom
377
- if( is_feed() ) {
378
- $newcontent = apply_filters("pmpro_rss_text_filter", stripslashes(pmpro_getOption("rsstext")));
379
- $content .= $pmpro_content_message_pre . str_replace($sr_search, $sr_replace, $newcontent) . $pmpro_content_message_post;
380
- } elseif( $current_user->ID ) {
381
- //not a member
382
- $newcontent = apply_filters("pmpro_non_member_text_filter", stripslashes(pmpro_getOption("nonmembertext")));
383
- $content .= $pmpro_content_message_pre . str_replace($sr_search, $sr_replace, $newcontent) . $pmpro_content_message_post;
384
- } else {
385
- //not logged in!
386
- $newcontent = apply_filters("pmpro_not_logged_in_text_filter", stripslashes(pmpro_getOption("notloggedintext")));
387
- $content .= $pmpro_content_message_pre . str_replace($sr_search, $sr_replace, $newcontent) . $pmpro_content_message_post;
388
- }
389
  }
390
 
391
  return $content;
@@ -395,7 +357,7 @@ add_filter('the_content_rss', 'pmpro_membership_content_filter', 5);
395
  add_filter('comment_text_rss', 'pmpro_membership_content_filter', 5);
396
 
397
  /*
398
- If the_excerpt is called, we want to disable the_content filters so the PMPro messages aren't added to the content before AND after the ecerpt.
399
  */
400
  function pmpro_membership_excerpt_filter($content, $skipcheck = false) {
401
  remove_filter('the_content', 'pmpro_membership_content_filter', 5);
347
  $content = "";
348
  }
349
 
350
+ $content = pmpro_get_no_access_message( $content, $post_membership_levels_ids, $post_membership_levels_names );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  }
352
 
353
  return $content;
357
  add_filter('comment_text_rss', 'pmpro_membership_content_filter', 5);
358
 
359
  /*
360
+ If the_excerpt is called, we want to disable the_content filters so the PMPro messages aren't added to the content before AND after the excerpt.
361
  */
362
  function pmpro_membership_excerpt_filter($content, $skipcheck = false) {
363
  remove_filter('the_content', 'pmpro_membership_content_filter', 5);
includes/functions.php CHANGED
@@ -668,7 +668,7 @@ function pmpro_next_payment( $user_id = null, $order_status = 'success', $format
668
 
669
  if ( ! empty( $order ) && ! empty( $order->id ) && ! empty( $level ) && ! empty( $level->id ) && ! empty( $level->cycle_number ) ) {
670
  // next payment date
671
- $nextdate = strtotime( '+' . $level->cycle_number . ' ' . $level->cycle_period, $order->timestamp );
672
 
673
  $r = $nextdate;
674
  } else {
@@ -1787,7 +1787,66 @@ function pmpro_actions_nav_separator() {
1787
  $separator = apply_filters( 'pmpro_actions_nav_separator', ' | ' );
1788
 
1789
  return $separator;
1790
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1791
 
1792
  /*
1793
  pmpro_getMembershipLevelForUser() returns the first active membership level for a user
@@ -2192,6 +2251,11 @@ function pmpro_getLevelAtCheckout( $level_id = null, $discount_code = null ) {
2192
  $pmpro_level = $wpdb->get_row( "SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql( $level_id ) . "' AND allow_signups = 1 LIMIT 1" );
2193
  }
2194
 
 
 
 
 
 
2195
  // filter the level (for upgrades, etc)
2196
  $pmpro_level = apply_filters( 'pmpro_checkout_level', $pmpro_level );
2197
 
668
 
669
  if ( ! empty( $order ) && ! empty( $order->id ) && ! empty( $level ) && ! empty( $level->id ) && ! empty( $level->cycle_number ) ) {
670
  // next payment date
671
+ $nextdate = strtotime( '+' . $level->cycle_number . ' ' . $level->cycle_period, $order->getTimestamp() );
672
 
673
  $r = $nextdate;
674
  } else {
1787
  $separator = apply_filters( 'pmpro_actions_nav_separator', ' | ' );
1788
 
1789
  return $separator;
1790
+ }
1791
+
1792
+ /**
1793
+ * pmpro_get_no_access_message to return the appropriate content message for the protected content.
1794
+ *
1795
+ * @param array $level_ids The array of level IDs this post is protected for.
1796
+ * @param array $level_names The array of names for the levels this post is protected for.
1797
+ *
1798
+ * @return string $content The appropriate content message for the given user/visitor and required levels.
1799
+ *
1800
+ */
1801
+ function pmpro_get_no_access_message( $content, $level_ids, $level_names = NULL ) {
1802
+ global $current_user;
1803
+
1804
+ if ( empty( $level_ids ) ) {
1805
+ $level_ids = array();
1806
+ }
1807
+
1808
+ if ( empty( $level_names ) ) {
1809
+ $level_names = array();
1810
+ foreach ( $level_ids as $key => $id ) {
1811
+ $level_obj = pmpro_getLevel( $id );
1812
+ $level_names[] = $level_obj->name;
1813
+ }
1814
+ }
1815
+
1816
+ // Hide levels which don't allow signups by default.
1817
+ if( ! apply_filters( 'pmpro_membership_content_filter_disallowed_levels', false, $level_ids, $level_names ) ) {
1818
+ foreach ( $level_ids as $key => $id ) {
1819
+ // Does this level allow registrations?
1820
+ $level_obj = pmpro_getLevel( $id );
1821
+ if ( empty( $level_obj ) || empty( $level_obj->allow_signups ) ) {
1822
+ unset( $level_ids[$key] );
1823
+ unset( $level_names[$key] );
1824
+ }
1825
+ }
1826
+ }
1827
+
1828
+ $pmpro_content_message_pre = '<div class="' . pmpro_get_element_class( 'pmpro_content_message' ) . '">';
1829
+ $pmpro_content_message_post = '</div>';
1830
+
1831
+ $sr_search = array( '!!levels!!', '!!referrer!!', '!!login_url!!', '!!login_page_url!!', '!!levels_url!!', '!!levels_page_url!!' );
1832
+ $sr_replace = array( pmpro_implodeToEnglish( $level_names ), urlencode( site_url( $_SERVER['REQUEST_URI'] ) ), esc_url( pmpro_login_url() ), esc_url( pmpro_login_url() ), esc_url( pmpro_url( 'levels' ) ), esc_url( pmpro_url( 'levels' ) ) );
1833
+
1834
+ // Get the correct message to show at the bottom.
1835
+ if ( is_feed() ) {
1836
+ $newcontent = apply_filters( 'pmpro_rss_text_filter', stripslashes( pmpro_getOption( 'rsstext' ) ) );
1837
+ $content .= $pmpro_content_message_pre . str_replace( $sr_search, $sr_replace, $newcontent ) . $pmpro_content_message_post;
1838
+ } elseif ( $current_user->ID ) {
1839
+ //not a member
1840
+ $newcontent = apply_filters( 'pmpro_non_member_text_filter', stripslashes( pmpro_getOption( 'nonmembertext' ) ) );
1841
+ $content .= $pmpro_content_message_pre . str_replace( $sr_search, $sr_replace, $newcontent ) . $pmpro_content_message_post;
1842
+ } else {
1843
+ //not logged in!
1844
+ $newcontent = apply_filters( 'pmpro_not_logged_in_text_filter', stripslashes( pmpro_getOption( 'notloggedintext' ) ) );
1845
+ $content .= $pmpro_content_message_pre . str_replace( $sr_search, $sr_replace, $newcontent ) . $pmpro_content_message_post;
1846
+ }
1847
+
1848
+ return $content;
1849
+ }
1850
 
1851
  /*
1852
  pmpro_getMembershipLevelForUser() returns the first active membership level for a user
2251
  $pmpro_level = $wpdb->get_row( "SELECT * FROM $wpdb->pmpro_membership_levels WHERE id = '" . esc_sql( $level_id ) . "' AND allow_signups = 1 LIMIT 1" );
2252
  }
2253
 
2254
+ // hide the confirmation message
2255
+ if ( ! empty( $pmpro_level->confirmation ) ) {
2256
+ $pmpro_level->confirmation = '';
2257
+ }
2258
+
2259
  // filter the level (for upgrades, etc)
2260
  $pmpro_level = apply_filters( 'pmpro_checkout_level', $pmpro_level );
2261
 
includes/metaboxes.php CHANGED
@@ -1,139 +1,140 @@
1
  <?php
2
- /*
3
- Require Membership Meta Box
4
- */
5
- function pmpro_page_meta()
6
- {
7
  global $post, $wpdb;
8
- $membership_levels = pmpro_getAllLevels(true, true);
9
- $page_levels = $wpdb->get_col("SELECT membership_id FROM {$wpdb->pmpro_memberships_pages} WHERE page_id = '{$post->ID}'");
10
  ?>
11
  <ul id="membershipschecklist" class="list:category categorychecklist form-no-clear">
12
- <input type="hidden" name="pmpro_noncename" id="pmpro_noncename" value="<?php echo wp_create_nonce( plugin_basename(__FILE__) )?>" />
13
  <?php
14
  $in_member_cat = false;
15
- foreach($membership_levels as $level)
16
- {
17
- ?>
18
- <li id="membership-level-<?php echo $level->id?>">
19
  <label class="selectit">
20
- <input id="in-membership-level-<?php echo $level->id?>" type="checkbox" <?php if(in_array($level->id, $page_levels)) { ?>checked="checked"<?php } ?> name="page_levels[]" value="<?php echo $level->id?>" />
21
  <?php
22
- echo $level->name;
23
  //Check which categories are protected for this level
24
- $protectedcategories = $wpdb->get_col("SELECT category_id FROM $wpdb->pmpro_memberships_categories WHERE membership_id = $level->id");
25
  //See if this post is in any of the level's protected categories
26
- if(in_category($protectedcategories, $post->id))
27
- {
28
  $in_member_cat = true;
29
  echo ' *';
30
  }
31
  ?>
32
  </label>
33
  </li>
34
- <?php
35
  }
36
  ?>
37
  </ul>
38
  <?php
39
- if('post' == get_post_type($post) && $in_member_cat) { ?>
40
  <p class="pmpro_meta_notice">* <?php _e("This post is already protected for this level because it is within a category that requires membership.", 'paid-memberships-pro' );?></p>
41
  <?php
42
  }
43
 
44
- do_action('pmpro_after_require_membership_metabox', $post);
45
  ?>
46
  <?php
47
  }
48
 
49
- //saves meta options
50
- function pmpro_page_save($post_id)
51
- {
 
52
  global $wpdb;
53
 
54
- if(empty($post_id))
55
  return false;
 
56
 
57
- if (!empty($_POST['pmpro_noncename']) && !wp_verify_nonce( $_POST['pmpro_noncename'], plugin_basename(__FILE__) )) {
 
58
  return $post_id;
59
  }
60
 
61
- // verify if this is an auto save routine. If it is our form has not been submitted, so we dont want
62
- // to do anything
63
- if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )
64
  return $post_id;
 
65
 
66
- // Check permissions
67
- if(!empty($_POST['post_type']) && 'page' == $_POST['post_type'] )
68
- {
69
- if ( !current_user_can( 'edit_page', $post_id ) )
70
- return $post_id;
71
  }
72
- else
73
- {
74
- if ( !current_user_can( 'edit_post', $post_id ) )
 
 
 
 
 
75
  return $post_id;
 
76
  }
77
 
78
- // OK, we're authenticated: we need to find and save the data
79
- if(isset($_POST['pmpro_noncename']))
80
- {
81
- if(!empty($_POST['page_levels']))
82
- $mydata = $_POST['page_levels'];
83
- else
84
- $mydata = NULL;
85
 
86
- //remove all memberships for this page
87
- $wpdb->query("DELETE FROM {$wpdb->pmpro_memberships_pages} WHERE page_id = '$post_id'");
88
 
89
- //add new memberships for this page
90
- if(is_array($mydata))
91
- {
92
- foreach($mydata as $level)
93
- $wpdb->query("INSERT INTO {$wpdb->pmpro_memberships_pages} (membership_id, page_id) VALUES('" . intval($level) . "', '" . intval($post_id) . "')");
94
  }
95
-
96
- return $mydata;
97
  }
98
- else
99
- return $post_id;
100
  }
101
 
102
- //wrapper to add meta boxes
103
- function pmpro_page_meta_wrapper()
104
- {
105
- add_meta_box('pmpro_page_meta', __('Require Membership', 'paid-memberships-pro' ), 'pmpro_page_meta', 'page', 'side', 'high' );
106
- add_meta_box('pmpro_page_meta', __('Require Membership', 'paid-memberships-pro' ), 'pmpro_page_meta', 'post', 'side', 'high' );
 
107
  }
108
- if (is_admin())
109
- {
110
- add_action('admin_menu', 'pmpro_page_meta_wrapper');
111
- add_action('save_post', 'pmpro_page_save');
112
  }
113
 
114
- //show membership level restrictions on category edit
115
- function pmpro_taxonomy_meta($term)
116
- {
 
117
  global $membership_levels, $post, $wpdb;
118
 
119
  $protectedlevels = array();
120
- foreach($membership_levels as $level)
121
- {
122
- $protectedlevel = $wpdb->get_col("SELECT category_id FROM $wpdb->pmpro_memberships_categories WHERE membership_id = $level->id AND category_id = $term->term_id");
123
- if(!empty($protectedlevel))
124
- $protectedlevels[] .= '<a target="_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . $level->id . '">' . $level->name. '</a>';
125
  }
126
- if(!empty($protectedlevels))
127
- {
128
- ?>
129
- <tr class="form-field">
130
- <th scope="row" valign="top"><?php _e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>
131
- <td>
132
- <p><strong>
133
- <?php echo implode(', ',$protectedlevels); ?></strong></p>
134
- <p class="description"><?php _e('Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>
135
- </td>
136
- </tr>
137
  <?php
138
  }
139
  }
1
  <?php
2
+ /**
3
+ * Require Membership Meta Box
4
+ */
5
+ function pmpro_page_meta() {
 
6
  global $post, $wpdb;
7
+ $membership_levels = pmpro_getAllLevels( true, true );
8
+ $page_levels = $wpdb->get_col( "SELECT membership_id FROM {$wpdb->pmpro_memberships_pages} WHERE page_id = '" . intval( $post->ID ) . "'" );
9
  ?>
10
  <ul id="membershipschecklist" class="list:category categorychecklist form-no-clear">
11
+ <input type="hidden" name="pmpro_noncename" id="pmpro_noncename" value="<?php echo esc_attr( wp_create_nonce( plugin_basename(__FILE__) ) )?>" />
12
  <?php
13
  $in_member_cat = false;
14
+ foreach( $membership_levels as $level ) {
15
+ ?>
16
+ <li id="membership-level-<?php echo esc_attr( $level->id ); ?>">
 
17
  <label class="selectit">
18
+ <input id="in-membership-level-<?php echo esc_attr( $level->id ); ?>" type="checkbox" <?php if(in_array($level->id, $page_levels)) { ?>checked="checked"<?php } ?> name="page_levels[]" value="<?php echo esc_attr( $level->id ) ;?>" />
19
  <?php
20
+ echo esc_html( $level->name );
21
  //Check which categories are protected for this level
22
+ $protectedcategories = $wpdb->get_col( "SELECT category_id FROM $wpdb->pmpro_memberships_categories WHERE membership_id = '" . intval( $level->id ) . "'");
23
  //See if this post is in any of the level's protected categories
24
+ if( in_category( $protectedcategories, $post->id ) ) {
 
25
  $in_member_cat = true;
26
  echo ' *';
27
  }
28
  ?>
29
  </label>
30
  </li>
31
+ <?php
32
  }
33
  ?>
34
  </ul>
35
  <?php
36
+ if( 'post' == get_post_type( $post ) && $in_member_cat ) { ?>
37
  <p class="pmpro_meta_notice">* <?php _e("This post is already protected for this level because it is within a category that requires membership.", 'paid-memberships-pro' );?></p>
38
  <?php
39
  }
40
 
41
+ do_action( 'pmpro_after_require_membership_metabox', $post );
42
  ?>
43
  <?php
44
  }
45
 
46
+ /**
47
+ * Saves meta options when a page is saved.
48
+ */
49
+ function pmpro_page_save( $post_id ) {
50
  global $wpdb;
51
 
52
+ if( empty( $post_id ) ) {
53
  return false;
54
+ }
55
 
56
+ // Post is saving somehow with our meta box not shown.
57
+ if ( ! isset( $_POST['pmpro_noncename'] ) ) {
58
  return $post_id;
59
  }
60
 
61
+ // Verify the nonce.
62
+ if ( ! wp_verify_nonce( $_POST['pmpro_noncename'], plugin_basename( __FILE__ ) ) ) {
 
63
  return $post_id;
64
+ }
65
 
66
+ // Don't try to update meta fields on AUTOSAVE.
67
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
68
+ return $post_id;
 
 
69
  }
70
+
71
+ // Check permissions.
72
+ if( ! empty( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
73
+ if ( ! current_user_can( 'edit_page', $post_id ) ) {
74
+ return $post_id;
75
+ }
76
+ } else {
77
+ if ( ! current_user_can( 'edit_post', $post_id ) ) {
78
  return $post_id;
79
+ }
80
  }
81
 
82
+ // OK, we're authenticated. We need to find and save the data.
83
+ if( ! empty( $_POST['page_levels'] ) ) {
84
+ $mydata = $_POST['page_levels'];
85
+ } else {
86
+ $mydata = NULL;
87
+ }
 
88
 
89
+ // Remove all memberships for this page.
90
+ $wpdb->query( "DELETE FROM {$wpdb->pmpro_memberships_pages} WHERE page_id = '" . intval( $post_id ) . "'" );
91
 
92
+ // Add new memberships for this page.
93
+ if( is_array( $mydata ) ) {
94
+ foreach( $mydata as $level ) {
95
+ $wpdb->query( "INSERT INTO {$wpdb->pmpro_memberships_pages} (membership_id, page_id) VALUES('" . intval( $level ) . "', '" . intval( $post_id ) . "')" );
 
96
  }
 
 
97
  }
98
+
99
+ return $mydata;
100
  }
101
 
102
+ /**
103
+ * Wrapper to add meta boxes
104
+ */
105
+ function pmpro_page_meta_wrapper() {
106
+ add_meta_box( 'pmpro_page_meta', __( 'Require Membership', 'paid-memberships-pro' ), 'pmpro_page_meta', 'page', 'side', 'high' );
107
+ add_meta_box( 'pmpro_page_meta', __( 'Require Membership', 'paid-memberships-pro' ), 'pmpro_page_meta', 'post', 'side', 'high' );
108
  }
109
+ if ( is_admin() ) {
110
+ add_action( 'admin_menu', 'pmpro_page_meta_wrapper' );
111
+ add_action( 'save_post', 'pmpro_page_save' );
 
112
  }
113
 
114
+ /**
115
+ * Show membership level restrictions on category edit.
116
+ */
117
+ function pmpro_taxonomy_meta( $term ) {
118
  global $membership_levels, $post, $wpdb;
119
 
120
  $protectedlevels = array();
121
+ foreach( $membership_levels as $level ) {
122
+ $protectedlevel = $wpdb->get_col( "SELECT category_id FROM $wpdb->pmpro_memberships_categories WHERE membership_id = '" . intval( $level->id ) . "' AND category_id = '" . intval( $term->term_id ) . "'" );
123
+ if( ! empty( $protectedlevel ) ) {
124
+ $protectedlevels[] .= '<a target="_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . intval( $level->id ) . '">' . esc_html( $level->name ) . '</a>';
125
+ }
126
  }
127
+
128
+ if( ! empty( $protectedlevels ) ) {
129
+ ?>
130
+ <tr class="form-field">
131
+ <th scope="row" valign="top"><?php _e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>
132
+ <td>
133
+ <p><strong>
134
+ <?php echo implode(', ',$protectedlevels); ?></strong></p>
135
+ <p class="description"><?php _e( 'Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>
136
+ </td>
137
+ </tr>
138
  <?php
139
  }
140
  }
includes/privacy.php CHANGED
@@ -235,7 +235,7 @@ function pmpro_personal_data_exporter( $email_address, $page = 1 ) {
235
  ),
236
  array(
237
  'name' => __( 'Order Date', 'paid-memberships-pro' ),
238
- 'value' => date( get_option( 'date_format' ), $order->timestamp ),
239
  ),
240
  array(
241
  'name' => __( 'Level', 'paid-memberships-pro' ),
235
  ),
236
  array(
237
  'name' => __( 'Order Date', 'paid-memberships-pro' ),
238
+ 'value' => date( get_option( 'date_format' ), $order->getTimestamp() ),
239
  ),
240
  array(
241
  'name' => __( 'Level', 'paid-memberships-pro' ),
includes/profile.php CHANGED
@@ -457,6 +457,15 @@ function pmpro_member_profile_edit_form() {
457
  }
458
  }
459
 
 
 
 
 
 
 
 
 
 
460
  // Show error messages.
461
  if ( ! empty( $errors ) ) { ?>
462
  <div class="<?php echo pmpro_get_element_class( 'pmpro_message pmpro_error', 'pmpro_error' ); ?>">
@@ -513,7 +522,7 @@ function pmpro_member_profile_edit_form() {
513
  <input type="text" readonly="readonly" name="user_email" id="user_email" value="<?php echo esc_attr( $user->user_email ); ?>" class="<?php echo pmpro_get_element_class( 'input', 'user_email' ); ?>" />
514
  <p class="<?php echo pmpro_get_element_class( 'lite' ); ?>"><?php esc_html_e( 'Site administrators must use the WordPress dashboard to update their email address.', 'paid-memberships-pro' ); ?></p>
515
  <?php } else { ?>
516
- <input type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" value="<?php echo esc_attr( $user->{$field_key} ); ?>" class="<?php echo pmpro_get_element_class( 'input', $field_key ); ?>" />
517
  <?php } ?>
518
  </div>
519
  <?php } ?>
457
  }
458
  }
459
 
460
+ /**
461
+ * Fires before member profile update errors are returned.
462
+ *
463
+ * @param $errors WP_Error object (passed by reference).
464
+ * @param $update Whether this is a user update.
465
+ * @param $user User object (passed by reference).
466
+ */
467
+ do_action_ref_array( 'pmpro_user_profile_update_errors', array( &$errors, $update, &$user ) );
468
+
469
  // Show error messages.
470
  if ( ! empty( $errors ) ) { ?>
471
  <div class="<?php echo pmpro_get_element_class( 'pmpro_message pmpro_error', 'pmpro_error' ); ?>">
522
  <input type="text" readonly="readonly" name="user_email" id="user_email" value="<?php echo esc_attr( $user->user_email ); ?>" class="<?php echo pmpro_get_element_class( 'input', 'user_email' ); ?>" />
523
  <p class="<?php echo pmpro_get_element_class( 'lite' ); ?>"><?php esc_html_e( 'Site administrators must use the WordPress dashboard to update their email address.', 'paid-memberships-pro' ); ?></p>
524
  <?php } else { ?>
525
+ <input type="text" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" value="<?php echo esc_attr( stripslashes( $user->{$field_key} ) ); ?>" class="<?php echo pmpro_get_element_class( 'input', $field_key ); ?>" />
526
  <?php } ?>
527
  </div>
528
  <?php } ?>
includes/rest-api.php CHANGED
@@ -138,12 +138,12 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
138
  array(
139
  'methods' => WP_REST_Server::READABLE,
140
  'callback' => array( $this, 'pmpro_rest_api_get_discount_code' ),
141
- 'permissions_callback' => array( $this, 'pmpro_rest_api_get_permissions_check' )
142
  ),
143
  array(
144
  'methods' => 'POST,PUT,PATCH',
145
  'callback' => array( $this, 'pmpro_rest_api_set_discount_code' ),
146
- 'permissions_callback' => array( $this, 'pmpro_rest_api_get_permissions_check' )
147
  ),
148
  ));
149
 
@@ -157,6 +157,7 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
157
  array(
158
  'methods' => WP_REST_Server::READABLE,
159
  'callback' => array( $this, 'pmpro_rest_api_get_checkout_level' ),
 
160
  ),
161
  ));
162
 
@@ -169,6 +170,7 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
169
  array(
170
  'methods' => WP_REST_Server::READABLE,
171
  'callback' => array( $this, 'pmpro_rest_api_get_checkout_levels' ),
 
172
  ),
173
  ));
174
  }
@@ -183,12 +185,22 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
183
 
184
  $user_id = isset( $params['user_id'] ) ? $params['user_id'] : null;
185
 
 
 
 
 
 
 
186
  if ( empty( $user_id ) && !empty( $params['email'] ) ) {
187
  $user = get_user_by_email( $params['email'] );
188
  $user_id = $user->ID;
189
  }
190
 
191
- $level = pmpro_getMembershipLevelForUser( $user_id );
 
 
 
 
192
 
193
  return new WP_REST_Response( $level, 200 );
194
  }
@@ -203,12 +215,22 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
203
 
204
  $user_id = isset( $params['user_id'] ) ? $params['user_id'] : null;
205
 
 
 
 
 
 
 
206
  if ( empty( $user_id ) && !empty( $params['email'] ) ) {
207
  $user = get_user_by_email( $params['email'] );
208
  $user_id = $user->ID;
209
  }
210
 
211
- $levels = pmpro_getMembershipLevelsForUser( $user_id );
 
 
 
 
212
 
213
  return new WP_REST_Response( $levels, 200 );
214
  }
@@ -234,7 +256,14 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
234
  }
235
  }
236
 
237
- $has_access = pmpro_has_membership_access( $post_id, $user_id );
 
 
 
 
 
 
 
238
  return new WP_REST_Response( $has_access, 200 );
239
  }
240
 
@@ -261,8 +290,14 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
261
  if ( ! function_exists( 'pmpro_changeMembershipLevel' ) ) {
262
  return new WP_REST_Response( 'Paid Memberships Pro function not found.', 404 );
263
  }
 
 
 
 
 
 
264
 
265
- return new WP_REST_Response( pmpro_changeMembershipLevel( $level_id, $user_id ), 200 );
266
  }
267
 
268
  /**
@@ -292,8 +327,14 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
292
  if ( ! function_exists( 'pmpro_cancelMembershipLevel' ) ) {
293
  return new WP_REST_Response( 'Paid Memberships Pro function not found.', 404 );
294
  }
295
-
296
- return new WP_REST_Response( pmpro_cancelMembershipLevel( $level_id, $user_id, 'inactive' ), 200 );
 
 
 
 
 
 
297
  }
298
 
299
  /**
@@ -314,7 +355,16 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
314
  return new WP_REST_Response( 'ID not passed through', 400 );
315
  }
316
 
317
- return new WP_REST_Response( new PMPro_Membership_Level( $id ), 200 );
 
 
 
 
 
 
 
 
 
318
  }
319
 
320
  /**
@@ -496,7 +546,7 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
496
  function pmpro_rest_api_get_checkout_level( $request ) {
497
  $params = $request->get_params();
498
 
499
- $level_id = isset( $params['level'] ) ? $params['level'] : null;
500
  if ( empty( $level_id ) ) {
501
  return new WP_REST_Response( 'No level found.', 400 );
502
  }
@@ -517,8 +567,8 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
517
  if ( ! empty( $pmpro_checkout_level_ids ) ) {
518
  // MMPU Compatibility...
519
  $level_ids = $pmpro_checkout_level_ids;
520
- } elseif ( isset( $_REQUEST['level'] ) ) {
521
- $level_ids = explode( '+', $_REQUEST['level'] );
522
  }
523
 
524
  if ( empty( $level_ids ) ) {
@@ -549,21 +599,41 @@ if ( class_exists( 'WP_REST_Controller' ) ) {
549
 
550
  $method = $request->get_method();
551
  $route = $request->get_route();
552
-
553
- // default permissions to 'read' (subscriber)
554
- $permissions = current_user_can('read');
555
- if ( $method != 'GET' ) {
556
- $permissions = current_user_can('pmpro_edit_memberships'); //Assume they can edit membership levels.
557
- }
558
 
559
- // Is the request method allowed?
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  if ( ! in_array( $method, pmpro_get_rest_api_methods( $route ) ) ) {
561
- $permissions = false;
562
  }
563
 
564
- $permissions = apply_filters( 'pmpro_rest_api_permissions', $permissions, $request );
565
 
566
- return $permissions;
567
  }
568
 
569
  /**
138
  array(
139
  'methods' => WP_REST_Server::READABLE,
140
  'callback' => array( $this, 'pmpro_rest_api_get_discount_code' ),
141
+ 'permission_callback' => array( $this, 'pmpro_rest_api_get_permissions_check' )
142
  ),
143
  array(
144
  'methods' => 'POST,PUT,PATCH',
145
  'callback' => array( $this, 'pmpro_rest_api_set_discount_code' ),
146
+ 'permission_callback' => array( $this, 'pmpro_rest_api_get_permissions_check' )
147
  ),
148
  ));
149
 
157
  array(
158
  'methods' => WP_REST_Server::READABLE,
159
  'callback' => array( $this, 'pmpro_rest_api_get_checkout_level' ),
160
+ 'permission_callback' => array( $this, 'pmpro_rest_api_get_permissions_check' )
161
  ),
162
  ));
163
 
170
  array(
171
  'methods' => WP_REST_Server::READABLE,
172
  'callback' => array( $this, 'pmpro_rest_api_get_checkout_levels' ),
173
+ 'permission_callback' => array( $this, 'pmpro_rest_api_get_permissions_check' )
174
  ),
175
  ));
176
  }
185
 
186
  $user_id = isset( $params['user_id'] ) ? $params['user_id'] : null;
187
 
188
+ // Param id was used instead (old style endpoint).
189
+ if ( empty( $user_id ) && !empty( $params['id'] ) ) {
190
+ $user_id = $params['id'];
191
+ }
192
+
193
+ // Query by email.
194
  if ( empty( $user_id ) && !empty( $params['email'] ) ) {
195
  $user = get_user_by_email( $params['email'] );
196
  $user_id = $user->ID;
197
  }
198
 
199
+ if ( ! empty( $user_id ) ) {
200
+ $level = pmpro_getMembershipLevelForUser( $user_id );
201
+ } else {
202
+ $level = false;
203
+ }
204
 
205
  return new WP_REST_Response( $level, 200 );
206
  }
215
 
216
  $user_id = isset( $params['user_id'] ) ? $params['user_id'] : null;
217
 
218
+ // Param id was used instead.
219
+ if ( empty( $user_id ) && !empty( $params['id'] ) ) {
220
+ $user_id = $params['id'];
221
+ }
222
+
223
+ // Param email was used instead.
224
  if ( empty( $user_id ) && !empty( $params['email'] ) ) {
225
  $user = get_user_by_email( $params['email'] );
226
  $user_id = $user->ID;
227
  }
228
 
229
+ if ( ! empty( $user_id ) ) {
230
+ $levels = pmpro_getMembershipLevelsForUser( $user_id );
231
+ } else {
232
+ $levels = false;
233
+ }
234
 
235
  return new WP_REST_Response( $levels, 200 );
236
  }
256
  }
257
  }
258
 
259
+ if ( ! empty( $user_id ) ) {
260
+ $has_access = pmpro_has_membership_access( $post_id, $user_id );
261
+ } else {
262
+ // No good user, so say no.
263
+ // Technically this will make public posts look restricted.
264
+ $has_access = false;
265
+ }
266
+
267
  return new WP_REST_Response( $has_access, 200 );
268
  }
269
 
290
  if ( ! function_exists( 'pmpro_changeMembershipLevel' ) ) {
291
  return new WP_REST_Response( 'Paid Memberships Pro function not found.', 404 );
292
  }
293
+
294
+ if ( ! empty( $user_id ) ) {
295
+ $response = pmpro_changeMembershipLevel( $level_id, $user_id );
296
+ } else {
297
+ $response = false;
298
+ }
299
 
300
+ return new WP_REST_Response( $response, 200 );
301
  }
302
 
303
  /**
327
  if ( ! function_exists( 'pmpro_cancelMembershipLevel' ) ) {
328
  return new WP_REST_Response( 'Paid Memberships Pro function not found.', 404 );
329
  }
330
+
331
+ if ( ! empty( $user_id ) ) {
332
+ $response = pmpro_cancelMembershipLevel( $level_id, $user_id, 'inactive' );
333
+ } else {
334
+ $response = false;
335
+ }
336
+
337
+ return new WP_REST_Response( $response, 200 );
338
  }
339
 
340
  /**
355
  return new WP_REST_Response( 'ID not passed through', 400 );
356
  }
357
 
358
+ $level = new PMPro_Membership_Level( $id );
359
+
360
+ // Hide confirmation message if not an admin or member.
361
+ if ( ! empty( $level->confirmation )
362
+ && ! pmpro_hasMembershipLevel( $id )
363
+ && ! current_user_can( 'pmpro_edit_memberships' ) ) {
364
+ $level->confirmation = '';
365
+ }
366
+
367
+ return new WP_REST_Response( $level, 200 );
368
  }
369
 
370
  /**
546
  function pmpro_rest_api_get_checkout_level( $request ) {
547
  $params = $request->get_params();
548
 
549
+ $level_id = isset( $params['level_id'] ) ? $params['level_id'] : null;
550
  if ( empty( $level_id ) ) {
551
  return new WP_REST_Response( 'No level found.', 400 );
552
  }
567
  if ( ! empty( $pmpro_checkout_level_ids ) ) {
568
  // MMPU Compatibility...
569
  $level_ids = $pmpro_checkout_level_ids;
570
+ } elseif ( isset( $_REQUEST['level_id'] ) ) {
571
+ $level_ids = explode( '+', $_REQUEST['level_id'] );
572
  }
573
 
574
  if ( empty( $level_ids ) ) {
599
 
600
  $method = $request->get_method();
601
  $route = $request->get_route();
 
 
 
 
 
 
602
 
603
+ // Default to requiring pmpro_edit_memberships capability.
604
+ $permission = current_user_can( 'pmpro_edit_memberships' );
605
+
606
+ // Check other caps for some routes.
607
+ $route_caps = array(
608
+ '/pmpro/v1/has_membership_access' => 'pmpro_edit_memberships',
609
+ '/pmpro/v1/get_membership_level_for_user' => 'pmpro_edit_memberships',
610
+ '/pmpro/v1/get_membership_levels_for_user' => 'pmpro_edit_memberships',
611
+ '/pmpro/v1/change_membership_level' => 'pmpro_edit_memberships',
612
+ '/pmpro/v1/cancel_membership_level' => 'pmpro_edit_memberships',
613
+ '/pmpro/v1/membership_level' => true,
614
+ '/pmpro/v1/discount_code' => 'pmpro_discountcodes',
615
+ '/pmpro/v1/checkout_level' => true,
616
+ '/pmpro/v1/checkout_levels' => true,
617
+ );
618
+ $route_caps = apply_filters( 'pmpro_rest_api_route_capabilities', $route_caps, $request );
619
+
620
+ if ( isset( $route_caps[$route] ) ) {
621
+ if ( $route_caps[$route] === true ) {
622
+ // public
623
+ $permission = true;
624
+ } else {
625
+ $permission = current_user_can( $route_caps[$route] );
626
+ }
627
+ }
628
+
629
+ // Is the request method allowed? We disable DELETE by default.
630
  if ( ! in_array( $method, pmpro_get_rest_api_methods( $route ) ) ) {
631
+ $permission = false;
632
  }
633
 
634
+ $permission = apply_filters( 'pmpro_rest_api_permissions', $permission, $request );
635
 
636
+ return $permission;
637
  }
638
 
639
  /**
includes/updates.php CHANGED
@@ -104,13 +104,11 @@ if(pmpro_isUpdateRequired() && (empty($_REQUEST['page']) || $_REQUEST['page'] !=
104
  */
105
  function pmpro_updates_notice() {
106
  ?>
107
- <div class="update-nag">
108
- <p>
109
  <?php
110
  echo __( 'Paid Memberships Pro Data Update Required', 'paid-memberships-pro' ) . '. ';
111
  echo sprintf(__( '(1) <a target="_blank" href="%s">Backup your WordPress database</a></strong> and then (2) <a href="%s">click here to start the update</a>.', 'paid-memberships-pro' ), 'https://codex.wordpress.org/WordPress_Backups#Database_Backup_Instructions', admin_url('admin.php?page=pmpro-updates'));
112
  ?>
113
- </p>
114
  </div>
115
  <?php
116
  }
104
  */
105
  function pmpro_updates_notice() {
106
  ?>
107
+ <div class="update-nag notice notice-warning inline">
 
108
  <?php
109
  echo __( 'Paid Memberships Pro Data Update Required', 'paid-memberships-pro' ) . '. ';
110
  echo sprintf(__( '(1) <a target="_blank" href="%s">Backup your WordPress database</a></strong> and then (2) <a href="%s">click here to start the update</a>.', 'paid-memberships-pro' ), 'https://codex.wordpress.org/WordPress_Backups#Database_Backup_Instructions', admin_url('admin.php?page=pmpro-updates'));
111
  ?>
 
112
  </div>
113
  <?php
114
  }
includes/updates/upgrade_1_8_9_3.php CHANGED
@@ -168,7 +168,7 @@ function pmpro_upgrade_1_8_9_3_ajax() {
168
  //calculate and fix the end date
169
  if(empty($user->membership_level->enddate)) {
170
  if ( ! empty( $pmpro_level->expiration_number ) ) {
171
- $enddate = date_i18n( "Y-m-d", strtotime( "+ " . $pmpro_level->expiration_number . " " . $pmpro_level->expiration_period, $last_order->timestamp ) );
172
  } else {
173
  $enddate = "NULL";
174
  }
168
  //calculate and fix the end date
169
  if(empty($user->membership_level->enddate)) {
170
  if ( ! empty( $pmpro_level->expiration_number ) ) {
171
+ $enddate = date_i18n( "Y-m-d", strtotime( "+ " . $pmpro_level->expiration_number . " " . $pmpro_level->expiration_period, $last_order->getTimestamp() ) );
172
  } else {
173
  $enddate = "NULL";
174
  }
languages/{paid-memberships-pro-vi_VN.mo → paid-memberships-pro-vi.mo} RENAMED
File without changes
languages/{paid-memberships-pro-vi_VN.po → paid-memberships-pro-vi.po} RENAMED
File without changes
pages/cancel.php CHANGED
@@ -73,10 +73,13 @@
73
  </td>
74
  <td class="<?php echo pmpro_get_element_class( 'pmpro_cancel-membership-expiration' ); ?>">
75
  <?php
76
- if($level->enddate)
77
- echo date_i18n(get_option('date_format'), $level->enddate);
78
- else
79
- echo "---";
 
 
 
80
  ?>
81
  </td>
82
  <td class="<?php echo pmpro_get_element_class( 'pmpro_cancel-membership-cancel' ); ?>">
73
  </td>
74
  <td class="<?php echo pmpro_get_element_class( 'pmpro_cancel-membership-expiration' ); ?>">
75
  <?php
76
+ if($level->enddate) {
77
+ $expiration_text = date_i18n( get_option( 'date_format' ), $level->enddate );
78
+ } else {
79
+ $expiration_text = "---";
80
+ }
81
+
82
+ echo apply_filters( 'pmpro_account_membership_expiration_text', $expiration_text, $level );
83
  ?>
84
  </td>
85
  <td class="<?php echo pmpro_get_element_class( 'pmpro_cancel-membership-cancel' ); ?>">
pages/confirmation.php CHANGED
@@ -44,7 +44,7 @@
44
  echo wp_kses_post( $confirmation_message );
45
  ?>
46
  <h3>
47
- <?php printf(__('Invoice #%s on %s', 'paid-memberships-pro' ), $pmpro_invoice->code, date_i18n(get_option('date_format'), $pmpro_invoice->timestamp));?>
48
  </h3>
49
  <a class="<?php echo pmpro_get_element_class( 'pmpro_a-print' ); ?>" href="javascript:window.print()"><?php _e('Print', 'paid-memberships-pro' );?></a>
50
  <ul>
44
  echo wp_kses_post( $confirmation_message );
45
  ?>
46
  <h3>
47
+ <?php printf(__('Invoice #%s on %s', 'paid-memberships-pro' ), $pmpro_invoice->code, date_i18n(get_option('date_format'), $pmpro_invoice->getTimestamp()));?>
48
  </h3>
49
  <a class="<?php echo pmpro_get_element_class( 'pmpro_a-print' ); ?>" href="javascript:window.print()"><?php _e('Print', 'paid-memberships-pro' );?></a>
50
  <ul>
pages/invoice.php CHANGED
@@ -18,7 +18,7 @@
18
  $pmpro_invoice->getUser();
19
  $pmpro_invoice->getMembershipLevel();
20
  ?>
21
- <h3><?php printf(__('Invoice #%s on %s', 'paid-memberships-pro' ), $pmpro_invoice->code, date_i18n(get_option('date_format'), $pmpro_invoice->timestamp));?></h3>
22
  <a class="<?php echo pmpro_get_element_class( 'pmpro_a-print' ); ?>" href="javascript:window.print()"><?php _e('Print', 'paid-memberships-pro' ); ?></a>
23
  <ul>
24
  <?php do_action("pmpro_invoice_bullets_top", $pmpro_invoice); ?>
@@ -119,7 +119,7 @@
119
  {
120
  ?>
121
  <tr>
122
- <td><a href="<?php echo pmpro_url("invoice", "?invoice=" . $invoice->code)?>"><?php echo date_i18n(get_option("date_format"), $invoice->timestamp)?></a></td>
123
  <td><a href="<?php echo pmpro_url("invoice", "?invoice=" . $invoice->code)?>"><?php echo $invoice->code; ?></a></td>
124
  <td><?php echo $invoice->membership_level_name;?></td>
125
  <td><?php echo pmpro_formatPrice($invoice->total);?></td>
18
  $pmpro_invoice->getUser();
19
  $pmpro_invoice->getMembershipLevel();
20
  ?>
21
+ <h3><?php printf(__('Invoice #%s on %s', 'paid-memberships-pro' ), $pmpro_invoice->code, date_i18n(get_option('date_format'), $pmpro_invoice->getTimestamp()));?></h3>
22
  <a class="<?php echo pmpro_get_element_class( 'pmpro_a-print' ); ?>" href="javascript:window.print()"><?php _e('Print', 'paid-memberships-pro' ); ?></a>
23
  <ul>
24
  <?php do_action("pmpro_invoice_bullets_top", $pmpro_invoice); ?>
119
  {
120
  ?>
121
  <tr>
122
+ <td><a href="<?php echo pmpro_url("invoice", "?invoice=" . $invoice->code)?>"><?php echo date_i18n(get_option("date_format"), $invoice->getTimestamp())?></a></td>
123
  <td><a href="<?php echo pmpro_url("invoice", "?invoice=" . $invoice->code)?>"><?php echo $invoice->code; ?></a></td>
124
  <td><?php echo $invoice->membership_level_name;?></td>
125
  <td><?php echo pmpro_formatPrice($invoice->total);?></td>
paid-memberships-pro.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Paid Memberships Pro
4
  * Plugin URI: https://www.paidmembershipspro.com
5
  * Description: The most complete member management and membership subscriptions plugin for WordPress.
6
- * Version: 2.4.1
7
  * Author: Stranger Studios
8
  * Author URI: https://www.strangerstudios.com
9
  * Text Domain: paid-memberships-pro
@@ -16,7 +16,7 @@
16
  */
17
 
18
  // version constant
19
- define( 'PMPRO_VERSION', '2.4.1' );
20
  define( 'PMPRO_USER_AGENT', 'Paid Memberships Pro v' . PMPRO_VERSION . '; ' . site_url() );
21
  define( 'PMPRO_MIN_PHP_VERSION', '5.6' );
22
 
3
  * Plugin Name: Paid Memberships Pro
4
  * Plugin URI: https://www.paidmembershipspro.com
5
  * Description: The most complete member management and membership subscriptions plugin for WordPress.
6
+ * Version: 2.4.3
7
  * Author: Stranger Studios
8
  * Author URI: https://www.strangerstudios.com
9
  * Text Domain: paid-memberships-pro
16
  */
17
 
18
  // version constant
19
+ define( 'PMPRO_VERSION', '2.4.3' );
20
  define( 'PMPRO_USER_AGENT', 'Paid Memberships Pro v' . PMPRO_VERSION . '; ' . site_url() );
21
  define( 'PMPRO_MIN_PHP_VERSION', '5.6' );
22
 
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: strangerstudios, kimannwall, andrewza, dlparker1005, paidmembershi
3
  Tags: memberships, members, subscriptions, ecommerce, user registration, member, membership, e-commerce, paypal, stripe, braintree, authorize.net, payflow, restrict access, restrict content, directory
4
  Requires at least: 4
5
  Tested up to: 5.5
6
- Stable tag: 2.4.1
7
 
8
  Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.
9
 
@@ -153,6 +153,26 @@ Not sure? You can find out by doing a bit a research.
153
  8. Membership Account page, display all sections or show specific sections using shortcode attributes.
154
 
155
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  = 2.4.1 - 2020-08-10 =
157
  * BUG FIX: Fixed issues with password resets on WP Engine hosting due to security features added by their mu-plugin.
158
  * BUG FIX: Fixed issue where end dates were showing up incorrectly in the confirmation email sometimes.
3
  Tags: memberships, members, subscriptions, ecommerce, user registration, member, membership, e-commerce, paypal, stripe, braintree, authorize.net, payflow, restrict access, restrict content, directory
4
  Requires at least: 4
5
  Tested up to: 5.5
6
+ Stable tag: 2.4.3
7
 
8
  Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.
9
 
153
  8. Membership Account page, display all sections or show specific sections using shortcode attributes.
154
 
155
  == Changelog ==
156
+ = 2.4.3 - 2020-08-25
157
+ * SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)
158
+ * SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.
159
+ * BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.
160
+
161
+ = 2.4.2 - 2020-08-24
162
+ * SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro_edit_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro_rest_api_route_capabilities filter and/or pmpro_rest_api_permissions filter to change this behavior.
163
+ * BUG FIX: Fixed issues with the PMPro REST API endpoints, including the discount code and checkout level endpoints.
164
+ * BUG FIX: Fixed issue with backslashes in the display name when editing form the PMPro frontend profile page.
165
+ * BUG FIX: Fixed issue where timestamps were showing up incorrectly for recent orders shown on the dashboard page.
166
+ BUG FIX: Fixed issue where PMPro would always try to add capabilities to the administrator role, even if you removed that role for some reason.
167
+ * ENHANCEMENT: Added a pmpro_get_no_access_message() function, which can be used to show the no access messages.
168
+ * ENHANCEMENT: Added a "show_noaccess" property to the membership shortcode. When set, it will show the noaccess message to users who don't have the levels specified.
169
+ * ENHANCEMENT: Added a pmpro_user_profile_update_errors hook, which can be used to show errors on the PMPro frontend profile page.
170
+ * ENHANCEMENT: The pmpro_set_capabilities_for_role() function now returns true or false if the caps were added in case others want to use this function and tell if it worked.
171
+ * ENHANCEMENT: You can now include links in the description of the fields you add to the PMPro advanced settings page via the pmpro_custom_advanced_settings filter.
172
+ * ENHANCEMENT: Updated the PayPal gateways to use the latest versions of the PayPal buttons.
173
+ * ENHANCEMENT: Fixed styling of the PMPro update script notice.
174
+ * ENHANCEMENT: Added the pmpro_account_membership_expiration_text filter to the expiration dates shown on the cancel page when using MMPU.
175
+
176
  = 2.4.1 - 2020-08-10 =
177
  * BUG FIX: Fixed issues with password resets on WP Engine hosting due to security features added by their mu-plugin.
178
  * BUG FIX: Fixed issue where end dates were showing up incorrectly in the confirmation email sometimes.
shortcodes/membership.php CHANGED
@@ -12,7 +12,8 @@ function pmpro_shortcode_membership($atts, $content=null, $code="")
12
  extract(shortcode_atts(array(
13
  'level' => NULL,
14
  'levels' => NULL,
15
- 'delay' => NULL
 
16
  ), $atts));
17
 
18
  //if levels is used instead of level
@@ -85,7 +86,13 @@ function pmpro_shortcode_membership($atts, $content=null, $code="")
85
  //to show or not to show
86
  if($hasaccess)
87
  return do_shortcode($content); //show content
88
- else
89
- return ""; //just hide it
 
 
 
 
 
 
90
  }
91
  add_shortcode("membership", "pmpro_shortcode_membership");
12
  extract(shortcode_atts(array(
13
  'level' => NULL,
14
  'levels' => NULL,
15
+ 'delay' => NULL,
16
+ 'show_noaccess' => NULL
17
  ), $atts));
18
 
19
  //if levels is used instead of level
86
  //to show or not to show
87
  if($hasaccess)
88
  return do_shortcode($content); //show content
89
+ else {
90
+ if ( empty( $show_noaccess ) ) {
91
+ return '';
92
+ } else {
93
+ $content = '';
94
+ return pmpro_get_no_access_message( $content, $levels );
95
+ }
96
+ }
97
  }
98
  add_shortcode("membership", "pmpro_shortcode_membership");
shortcodes/pmpro_account.php CHANGED
@@ -237,7 +237,7 @@ function pmpro_shortcode_account($atts, $content=null, $code="")
237
  }
238
  ?>
239
  <tr id="pmpro_account-invoice-<?php echo $invoice->code; ?>">
240
- <td><a href="<?php echo pmpro_url("invoice", "?invoice=" . $invoice->code)?>"><?php echo date_i18n(get_option("date_format"), $invoice->timestamp)?></td>
241
  <td><?php if(!empty($invoice->membership_level)) echo $invoice->membership_level->name; else echo __("N/A", 'paid-memberships-pro' );?></td>
242
  <td><?php echo pmpro_formatPrice($invoice->total)?></td>
243
  <td><?php echo $display_status; ?></td>
237
  }
238
  ?>
239
  <tr id="pmpro_account-invoice-<?php echo $invoice->code; ?>">
240
+ <td><a href="<?php echo pmpro_url("invoice", "?invoice=" . $invoice->code)?>"><?php echo date_i18n(get_option("date_format"), $invoice->getTimestamp())?></td>
241
  <td><?php if(!empty($invoice->membership_level)) echo $invoice->membership_level->name; else echo __("N/A", 'paid-memberships-pro' );?></td>
242
  <td><?php echo pmpro_formatPrice($invoice->total)?></td>
243
  <td><?php echo $display_status; ?></td>