WP-Members Membership Plugin - Version 3.3.4

Version Description

  • Updated pre_get_posts to merge post__not_in with any existing values. This will allow for better integration with other plugins (such as Search Exclude).
  • Updated pre_get_posts to fire later (20) in case another plugin is adding values to be excluded. This will prevent any hidden posts from being dropped by the other plugin's process.
  • Added wpmem_hidden_posts and wpmem_posts__not_in filters.
  • Fixed logic in upload input type (image or file) to correct undefined variable ($file_type).
  • Added function_exists check for wpmem_renew() (a PayPal extension function used in the core plugin).
  • Fixed function name typo for wpmem_a_extend_user() (a PayPal extension function used in the core plugin).
  • Updated product access shortcode error message to use the product_restricted message and changed the class to product_restricted_msg
  • Updated CAPTCHA class for more flexibility (can now be implemented into API for calling directly in the login or other forms).
  • Moved user export function from Admin API to User API.
  • Fixed adding WP-Members fields to WooCommerce checkout.
Download this release

Release Info

Developer cbutlerjr
Plugin Icon 128x128 WP-Members Membership Plugin
Version 3.3.4
Comparing to
See all releases

Code changes from version 3.3.3 to 3.3.4

assets/css/admin.css CHANGED
@@ -115,4 +115,11 @@
115
  }
116
  #wpmem_user_profile_tabs .ui-state-active a {
117
  color: #fff;
118
- }
 
 
 
 
 
 
 
115
  }
116
  #wpmem_user_profile_tabs .ui-state-active a {
117
  color: #fff;
118
+ }
119
+
120
+ #wpmem_product_fixed_period_select input,
121
+ #wpmem_product_no_gap,
122
+ #wpmem_product_fixed_period {
123
+ margin-top: 10px;
124
+ margin-left: 24px;
125
+ }
includes/admin/api.php CHANGED
@@ -95,23 +95,4 @@ function wpmem_admin_form_post_url( $args = false ) {
95
  function wpmem_wp_reserved_terms() {
96
  global $wpmem;
97
  return $wpmem->admin->wp_reserved_terms();
98
- }
99
-
100
- /**
101
- * Export all or selected users
102
- *
103
- * @since 2.9.7
104
- * @since 3.2.0 Updated to use fputcsv.
105
- * @since 3.2.1 Added user data filters.
106
- * @since 3.3.0 Call object class static method.
107
- *
108
- * @global object $wpmem
109
- *
110
- * @param array $args
111
- * @param array $users
112
- */
113
- function wpmem_export_users( $args, $users = null ) {
114
- global $wpmem;
115
- include_once( $wpmem->path . 'includes/admin/class-wp-members-export.php' );
116
- WP_Members_Export::export_users( $args, $users );
117
  }
95
  function wpmem_wp_reserved_terms() {
96
  global $wpmem;
97
  return $wpmem->admin->wp_reserved_terms();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
includes/admin/class-wp-members-products-admin.php CHANGED
@@ -1,574 +1,677 @@
1
- <?php
2
- /**
3
- * The WP_Members Products Admin Class.
4
- *
5
- * @package WP-Members
6
- * @subpackage WP_Members_Products_Admin
7
- * @since 3.2.0
8
- */
9
-
10
- // Exit if accessed directly.
11
- if ( ! defined( 'ABSPATH' ) ) {
12
- exit();
13
- }
14
-
15
- class WP_Members_Products_Admin {
16
-
17
- /**
18
- * Class constructor.
19
- *
20
- * @since 3.2.0
21
- *
22
- * @global object $wpmem
23
- */
24
- function __construct() {
25
- global $wpmem;
26
- if ( 1 == $wpmem->enable_products ) {
27
- add_filter( 'manage_wpmem_product_posts_columns', array( $this, 'columns_heading' ) );
28
- add_action( 'manage_wpmem_product_posts_custom_column', array( $this, 'columns_content' ), 10, 2 );
29
- add_action( 'add_meta_boxes', array( $this, 'meta_boxes' ) );
30
- add_action( 'save_post', array( $this, 'save_details' ) );
31
- add_action( 'wpmem_admin_after_block_meta', array( $this, 'add_product_to_post' ), 10, 2 );
32
- add_action( 'wpmem_admin_block_meta_save', array( $this, 'save_product_to_post' ), 10, 3 );
33
- add_action( 'admin_footer', array( $this, 'enqueue_select2' ) );
34
- add_filter( 'manage_users_columns', array( $this, 'user_columns' ) );
35
- add_filter( 'manage_users_custom_column', array( $this, 'user_columns_content' ), 10, 3 );
36
- add_filter( 'manage_posts_columns', array( $this, 'post_columns' ) );
37
- add_action( 'manage_posts_custom_column', array( $this, 'post_columns_content' ), 10, 2 );
38
- add_filter( 'manage_pages_columns', array( $this, 'post_columns' ) );
39
- add_action( 'manage_pages_custom_column', array( $this, 'post_columns_content' ), 10, 2 );
40
- foreach( $wpmem->post_types as $key => $val ) {
41
- add_filter( 'manage_' . $key . '_posts_columns', array( $this, 'post_columns' ) );
42
- add_action( 'manage_' . $key . '_posts_custom_column', array( $this, 'post_columns_content' ), 10, 2 );
43
- }
44
-
45
- add_filter( 'wpmem_user_profile_tabs', array( $this, 'user_profile_tabs' ), 1 );
46
- add_action( 'wpmem_user_profile_tabs_content', array( $this, 'user_profile_tab_content' ), 10 );
47
- }
48
-
49
- $this->default_products = $wpmem->membership->get_default_products();
50
- }
51
-
52
- /**
53
- * Column headings for list table.
54
- *
55
- * @since 3.2.0
56
- *
57
- * @param array $columns
58
- * @return array $columns
59
- */
60
- function columns_heading( $columns ) {
61
- unset( $columns['date'] );
62
- $columns['slug'] = __( 'Slug', 'wp-members' );
63
- $columns['role'] = __( 'Role', 'wp-members' );
64
- $columns['expires'] = __( 'Expires', 'wp-members' );
65
- if ( $this->default_products ) {
66
- $columns['default_products'] = __( 'Default', 'wp-members' );
67
- }
68
- $columns['last_updated'] = __( 'Last updated', 'wp-members' );
69
- return $columns;
70
- }
71
-
72
- /**
73
- * Column content for list table.
74
- *
75
- * @since 3.2.0
76
- *
77
- * @param string $column_name
78
- * @param int $post_id
79
- */
80
- function columns_content( $column, $post_id ) {
81
- $post = get_post( $post_id );
82
- switch ( $column ) {
83
- case 'slug':
84
- echo $post->post_name;
85
- break;
86
- case 'role':
87
- $role_slug = $this->get_meta( 'wpmem_product_role' );
88
- if ( $role_slug ) {
89
- $wp_roles = new WP_Roles;
90
- $names = $wp_roles->get_names();
91
-
92
- $role = $names[ $role_slug ] . ' (' . __( 'slug:', 'wp-members' ) . ' ' . $role_slug . ')';
93
- echo esc_html( $role );
94
- } else {
95
- __( 'No role required', 'wp-members' );
96
- }
97
- break;
98
- case 'expires':
99
- $expires = $this->get_meta( 'wpmem_product_expires' );
100
- $period = ( false !== $expires ) ? explode( "|", $expires[0] ) : __( 'Does not expire', 'wp-members' );
101
- echo ( is_array( $period ) ) ? esc_html( $period[0] . ' ' . $period[1] ) : esc_html( $period );
102
- break;
103
- case 'default_products':
104
- echo ( in_array( $post->post_name, $this->default_products ) ) ? __( 'Yes', 'wp-members' ) : '';
105
- break;
106
- case 'last_updated':
107
- echo date_i18n( get_option( 'date_format' ), strtotime( esc_attr( $post->post_modified ) ) );
108
- break;
109
- }
110
- }
111
-
112
- /**
113
- * Gets value of requested post meta.
114
- *
115
- * @since 3.2.0
116
- *
117
- * @param string $value
118
- * @return string
119
- */
120
- function get_meta( $value ) {
121
- global $post;
122
- $field = get_post_meta( $post->ID, $value, true );
123
- if ( ! empty( $field ) ) {
124
- return is_array( $field ) ? stripslashes_deep( $field ) : stripslashes( wp_kses_decode_entities( $field ) );
125
- } else {
126
- return false;
127
- }
128
- }
129
-
130
- /**
131
- * Handles meta boxes for CPT editor.
132
- *
133
- * @since 3.2.0
134
- */
135
- function meta_boxes() {
136
- remove_meta_box( 'slugdiv', 'wpmem_product', 'normal' );
137
- add_meta_box(
138
- 'membership_product',
139
- __( 'Membership Product Details', 'wp-members' ),
140
- array( $this, 'details_html' ),
141
- 'wpmem_product',
142
- 'normal',
143
- 'high'
144
- );
145
- }
146
-
147
- /**
148
- * Gets an array of post types.
149
- *
150
- * @since 3.3.3
151
- *
152
- * @return array $post_types
153
- */
154
- function get_post_types() {
155
- global $wpmem;
156
- // @todo This comes from option tab. Should consider it being an api function.
157
- $post_arr = array(
158
- 'post' => __( 'Posts' ),
159
- 'page' => __( 'Pages' ),
160
- );
161
- if ( ! empty( $wpmem->post_types ) ) {
162
- foreach ( $wpmem->post_types as $key => $post_type ) {
163
- $post_arr[ $key ] = $post_type;
164
- }
165
- }
166
- return $post_arr;
167
- }
168
-
169
- /**
170
- * Outputs HTML for CPT editor.
171
- *
172
- * @since 3.2.0
173
- *
174
- * @param object $post
175
- */
176
- function details_html( $post ) {
177
-
178
- $product_default = $this->get_meta( 'wpmem_product_default' );
179
- $product_expires = $this->get_meta( 'wpmem_product_expires' );
180
- $product_role = $this->get_meta( 'wpmem_product_role' );
181
- $product_no_gap = $this->get_meta( 'wpmem_product_no_gap' );
182
-
183
- $product_expires = ( false !== $product_expires ) ? $product_expires[0] : $product_expires;
184
-
185
- $periods = array( __( 'Period', 'wp-members' ) . '|', __( 'Day', 'wp-members' ) . '|day', __( 'Week', 'wp-members' ) . '|week', __( 'Month', 'wp-members' ) . '|month', __( 'Year', 'wp-members' ) . '|year' );
186
- $show_role_detail = ( false !== $product_role ) ? 'show' : 'hide';
187
- $show_exp_detail = ( false !== $product_expires ) ? 'show' : 'hide'; ?>
188
-
189
- <?php wp_nonce_field( '_wpmem_product_nonce', 'wpmem_product_nonce' ); ?>
190
- <h3><?php _e( 'Name (slug)', 'wp-members' ); ?></h3>
191
- <p><strong><?php echo esc_attr( $post->post_name ); ?></strong></p>
192
- <h3><?php esc_html_e( 'Optional Defaults', 'wp-members' ); ?></h3>
193
- <p>
194
- <input type="checkbox" name="wpmem_product_default" id="wpmem_product_default" value="1" <?php echo ( 1 == $product_default ) ? 'checked' : ''; ?> />
195
- <label for="wpmem_product_default"><?php _e( 'Assign as default at registration? (optional)', 'wp-members' ); ?></label>
196
- </p>
197
- <p>
198
- <?php
199
-
200
- foreach( $this->get_post_types() as $key => $post_type ) {
201
- echo '<div>';
202
- echo '<input type="checkbox" name="wpmem_product_set_default_' . $key . '" id="wpmem_product_set_default_' . $key . '" value ="1" '; echo ( 1 == $this->get_meta( "wpmem_product_set_default_" . $key ) ) ? 'checked' : ''; echo ' />';
203
- echo '<label for="wpmem_product_set_default_' . $key . '">' . sprintf( esc_html__( 'Pre-selected by default for new %s', 'wp-members' ), $post_type ) . '</label>';
204
- echo '</div>';
205
- }
206
-
207
- ?>
208
- </p>
209
- <h3><?php esc_html_e( 'Optional Properties', 'wp-members' ); ?></h3>
210
- <p>
211
- <input type="checkbox" name="wpmem_product_role_required" id="wpmem_product_role_required" value="role-required" <?php echo ( false !== $product_role ) ? 'checked' : ''; ?> />
212
- <label for="wpmem_product_role_required"><?php _e( 'Role Required? (optional)', 'wp-members' ); ?></label>
213
- <label for="wpmem_product_role"></label>
214
- <select name="wpmem_product_role" id="wpmem_product_role">
215
- <option value=""><?php _e( 'No Role', 'wp-members' ); ?></option>
216
- <?php wp_dropdown_roles( $this->get_meta( 'wpmem_product_role' ) ); ?>
217
- </select>
218
- </p>
219
- <p>
220
- <input type="checkbox" name="wpmem_product_expires" id="wpmem_product_expires" value="expires" <?php echo ( false !== $product_expires ) ? 'checked' : ''; ?> />
221
- <label for="wpmem_product_expires"><?php _e( 'Expires (optional)', 'wp-members' ); ?></label>
222
- <span id="wpmem_product_expires_wrap">
223
- <label for="wpmem_product_number_of_periods" style="display:none;"><?php _e( 'Number', 'wp-members' ); ?></label>
224
- <?php $period = explode( '|', $product_expires ); ?>
225
- <input type="text" name="wpmem_product_number_of_periods" id="wpmem_product_number_of_periods" value="<?php echo esc_attr( $period[0] ); ?>" class="small-text" placeholder="<?php _e( 'Number', 'wp-members' ); ?>" style="width:66px;height:28px;vertical-align:middle;">
226
- <label for="wpmem_product_time_period" style="display:none;"><?php _e( 'Period', 'wp-members' ); ?></label>
227
- <?php echo wpmem_form_field( array( 'name'=>'wpmem_product_time_period', 'type'=>'select', 'value'=>$periods, 'compare'=>( ( isset( $period[1] ) ) ? $period[1] : '' ) ) ); ?>
228
- <label><?php esc_html_e( 'Use "no gap" renewal', 'wp-members' ); ?></label>
229
- <?php echo wpmem_form_field( array( 'name'=>'wpmem_product_no_gap', 'type'=>'checkbox', 'value'=>'1', 'compare'=>( ( isset( $product_no_gap ) ) && 1 == $product_no_gap ) ? $product_no_gap : '' ) ); ?>
230
- </span>
231
- </p>
232
- <script>
233
- (function($) {
234
- $(document).ready(function() {
235
- $("#wpmem_product_role").<?php echo ( $show_role_detail ); ?>();
236
- $("#wpmem_product_expires_wrap").<?php echo ( $show_exp_detail ); ?>();
237
- });
238
- $(document).ready(function() {
239
- $('#wpmem_product_role_required').on('change', function (){
240
- if ($(this).is(':checked')) {
241
- $('#wpmem_product_role').show();
242
- } else {
243
- $('#wpmem_product_role').hide();
244
- }
245
- });
246
- $('#wpmem_product_expires').on('change', function (){
247
- if ($(this).is(':checked')) {
248
- $('#wpmem_product_expires_wrap').show();
249
- } else {
250
- $('#wpmem_product_expires_wrap').hide();
251
- }
252
- });
253
- });
254
- })(jQuery);
255
- </script><?php
256
- }
257
-
258
- /**
259
- * Saves meta fields for CPT
260
- *
261
- * @since 3.2.0
262
- *
263
- * @param int $post_id
264
- */
265
- function save_details( $post_id ) {
266
-
267
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
268
- if ( ! isset( $_POST['wpmem_product_nonce'] ) || ! wp_verify_nonce( $_POST['wpmem_product_nonce'], '_wpmem_product_nonce' ) ) return;
269
- if ( ! current_user_can( 'edit_posts', $post_id ) ) return;
270
-
271
- $post = get_post( $post_id );
272
-
273
- $product_name = wpmem_get( 'wpmem_product_name', false );
274
- $product_name = ( $product_name ) ? $product_name : $post->post_name;
275
- update_post_meta( $post_id, 'wpmem_product_name', sanitize_text_field( $product_name ) );
276
-
277
- $product_default = wpmem_get( 'wpmem_product_default', false );
278
- update_post_meta( $post_id, 'wpmem_product_default', ( ( $product_default ) ? true : false ) );
279
-
280
- $role_required = wpmem_get( 'wpmem_product_role_required', false );
281
- if ( ! $role_required ) {
282
- update_post_meta( $post_id, 'wpmem_product_role', false );
283
- } else {
284
- update_post_meta( $post_id, 'wpmem_product_role', sanitize_text_field( wpmem_get( 'wpmem_product_role' ) ) );
285
- }
286
-
287
- $expires = wpmem_get( 'wpmem_product_expires', false );
288
- if ( ! $expires ) {
289
- update_post_meta( $post_id, 'wpmem_product_expires', false );
290
- } else {
291
- $number = sanitize_text_field( wpmem_get( 'wpmem_product_number_of_periods' ) );
292
- $period = sanitize_text_field( wpmem_get( 'wpmem_product_time_period' ) );
293
- $no_gap = sanitize_text_field( wpmem_get( 'wpmem_product_no_gap' ) );
294
- $expires_array = array( $number . "|" . $period );
295
- update_post_meta( $post_id, 'wpmem_product_expires', $expires_array );
296
- if ( $no_gap ) {
297
- update_post_meta( $post_id, 'wpmem_product_no_gap', 1 );
298
- } else {
299
- delete_post_meta( $post_id, 'wpmem_product_no_gap' );
300
- }
301
- }
302
- foreach( $this->get_post_types() as $key => $post_type ) {
303
- if ( false !== wpmem_get( 'wpmem_product_set_default_' . $key, false ) ) {
304
- update_post_meta( $post_id, 'wpmem_product_set_default_' . $key, 1 );
305
- } else {
306
- delete_post_meta( $post_id, 'wpmem_product_set_default_' . $key );
307
- }
308
- }
309
- }
310
-
311
- /**
312
- * Add dropdown to post and page meta box for marking access by product..
313
- *
314
- * @since 3.2.0
315
- * @since 3.3.3 Added defaults.
316
- *
317
- * @global object $pagenow
318
- * @global object $wpmem
319
- * @param object $post
320
- * @param string $block
321
- */
322
- function add_product_to_post( $post, $block ) {
323
- global $pagenow, $wpmem;
324
-
325
- // For checking default memberships.
326
- $is_new = ( 'post-new.php' == $pagenow ) ? true : false;
327
-
328
- $product = $wpmem->membership->get_post_products( $post->ID ); //get_post_meta( $post->ID, $wpmem->membership->post_meta, true );
329
- $product = ( $product ) ? $product : array();
330
- $values[] = __( 'None', 'wp-members' ) . '|';
331
-
332
- foreach ( $wpmem->membership->products as $key => $value ) {
333
-
334
- if ( $is_new ) {
335
- if ( isset( $value[ 'set_default_' . $post->post_type ] ) && 1 == $value[ 'set_default_' . $post->post_type ] ) {
336
- $product[] = $key;
337
- }
338
- }
339
-
340
- $values[] = $value['title'] . '|' . $key;
341
- }
342
-
343
- echo wpmem_form_label( array(
344
- 'meta_key'=>$wpmem->membership->post_meta,
345
- 'label'=>__( 'Limit access to:', 'wp-members' ),
346
- 'type'=> 'multiselect'
347
- ) );
348
- echo "<br />";
349
- echo wpmem_form_field( array(
350
- 'name' => $wpmem->membership->post_meta,
351
- 'type' => 'multiselect',
352
- 'value' => $values,
353
- 'compare' => $product,
354
- 'class' => 'wpmem-product-select2',
355
- ) );
356
- }
357
-
358
- /**
359
- * Save custom post meta for access by product.
360
- *
361
- * @since 3.2.0
362
- *
363
- * @global object $wpmem
364
- * @param object $post
365
- */
366
- function save_product_to_post( $post ) {
367
- global $wpmem;
368
- $products = wpmem_get( $wpmem->membership->post_meta );
369
- $products = ( $products ) ? $products : array();
370
- if ( empty( $products ) || ( 1 == count( $products ) && '' == $products[0] ) ) {
371
- delete_post_meta( $post->ID, $wpmem->membership->post_meta );
372
- } else {
373
- update_post_meta( $post->ID, $wpmem->membership->post_meta, $products );
374
- }
375
- foreach ( $wpmem->membership->products as $key => $value ) {
376
- if ( in_array( $key, $products ) ) {
377
- update_post_meta( $post->ID, $wpmem->membership->post_stem . $key, 1 );
378
- } else {
379
- delete_post_meta( $post->ID, $wpmem->membership->post_stem . $key );
380
- }
381
- }
382
- }
383
-
384
- /**
385
- * Enqueue select2 JS.
386
- *
387
- * @since 3.2.3
388
- */
389
- function enqueue_select2() {
390
- $screen = get_current_screen();
391
- if ( $screen->base == 'post' && $screen->parent_base == 'edit' ) { ?>
392
- <script language="javascript">
393
- (function($) {
394
- $(document).ready(function() {
395
- $('.wpmem-product-select2').select2();
396
- });
397
- })(jQuery);
398
- </script><?php
399
- }
400
- }
401
-
402
- /**
403
- * Add membership product column to post table.
404
- *
405
- * @since 3.2.4
406
- *
407
- * @global object $wpmem
408
- * @param array $columns
409
- * @return array $columns
410
- */
411
- function post_columns( $columns ){
412
- global $wpmem;
413
- $post_type = ( isset( $_REQUEST['post_type'] ) ) ? sanitize_text_field( $_REQUEST['post_type'] ) : 'post';
414
- if ( $post_type == 'page' || $post_type == 'post' || array_key_exists( $post_type, $wpmem->post_types ) ) {
415
- $product = array( 'wpmem_product' => __( 'Required Membership', 'wp-members' ) );
416
- $columns = wpmem_array_insert( $columns, $product, 'wpmem_block', 'before' );
417
- }
418
- return $columns;
419
- }
420
-
421
- /**
422
- * Membership product column data.
423
- *
424
- * @since 3.2.4
425
- *
426
- * @global object $wpmem
427
- * @param string $column_name
428
- * @param int $post_id
429
- */
430
- function post_columns_content( $column_name, $post_id ) {
431
- if ( 'wpmem_product' == $column_name ) {
432
- global $wpmem;
433
- $post_products = $wpmem->membership->get_post_products( $post_id );
434
- if ( $post_products ) {
435
- foreach ( $post_products as $meta ) {
436
- if ( isset( $wpmem->membership->products[ $meta ]['title'] ) ) {
437
- $display[] = $wpmem->membership->products[ $meta ]['title'];
438
- }
439
- }
440
- echo implode( ", ", $display );
441
- }
442
- }
443
- }
444
-
445
- /**
446
- * Add membership product column to post table.
447
- *
448
- * @since 3.2.4
449
- *
450
- * @param array $columns
451
- * @return array $columns
452
- */
453
- function user_columns( $columns ){
454
- $columns['wpmem_product'] = __( 'Membership', 'wp-members' );
455
- return $columns;
456
- }
457
-
458
- /**
459
- * Membership product column data.
460
- *
461
- * @since 3.2.4
462
- *
463
- * @global object $wpmem
464
- * @param string $column_name
465
- * @param int $post_id
466
- * @return array $display
467
- */
468
- function user_columns_content( $val, $column_name, $user_id ) {
469
- if ( 'wpmem_product' == $column_name ) {
470
- global $wpmem;
471
- $display = array();
472
- $user_products = $wpmem->user->get_user_products( $user_id );
473
- if ( $user_products ) {
474
- foreach ( $user_products as $meta => $value ) {
475
- if ( isset( $wpmem->membership->products[ $meta ]['title'] ) ) {
476
- $display[] = $wpmem->membership->products[ $meta ]['title'];
477
- }
478
- }
479
- }
480
- return implode( ", ", $display );
481
- }
482
- return $val;
483
- }
484
-
485
- /**
486
- * Creates tab for user profile.
487
- *
488
- * @since
489
- *
490
- * @param array $tabs
491
- */
492
- function user_profile_tabs( $tabs ) {
493
- $tabs['memberships'] = array(
494
- 'tab' => __( 'Memberships', 'wp-members' ),
495
- );
496
- return $tabs;
497
- }
498
-
499
- /**
500
- * Add user product access to user profile.
501
- *
502
- * @since 3.2.0
503
- *
504
- * @global string $pagenow
505
- * @global object $wpmem
506
- * @param string $key
507
- */
508
- public function user_profile_tab_content( $key ) {
509
- // If product enabled
510
- if ( 'memberships' == $key ) {
511
- global $pagenow, $wpmem;
512
- /*
513
- * If an admin is editing their provile, we need their ID,
514
- * otherwise, it's the user_id param from the URL. It's a
515
- * little more complicated than it sounds since you can't just
516
- * check if the user is logged in, because the admin is always
517
- * logged in when checking profiles.
518
- */
519
- $user_id = ( 'profile' == $pagenow && current_user_can( 'edit_users' ) ) ? get_current_user_id() : sanitize_text_field( wpmem_get( 'user_id', false, 'get' ) );
520
- $user_products = $wpmem->user->get_user_products( $user_id );
521
- echo '<h3>' . __( 'Product Access', 'wp-members' ) . '</h3>';
522
- echo '<table>
523
- <tr>
524
- <th>' . __( 'Status', 'wp-members' ) . '</th>
525
- <th>' . __( 'Membership', 'wp-members' ) . '</th>
526
- <th>' . __( 'Enabled?', 'wp-members' ) . '</th>
527
- <th>' . __( 'Expires', 'wp-members' ) . '</th>
528
- </tr>'; ?>
529
- <?php
530
- foreach ( $wpmem->membership->products as $key => $value ) {
531
- $checked = ( $user_products && array_key_exists( $key, $user_products ) ) ? "checked" : "";
532
- echo "<tr>";
533
- echo '<td style="padding:5px 5px;">
534
- <select name="_wpmem_membership_product[' . $key . ']">
535
- <option value="">----</option>
536
- <option value="enable">' . __( 'Enable', 'wp-members' ) . '</option>
537
- <option value="disable">' . __( 'Disable', 'wp-members' ) . '</option>
538
- </select></td><td style="padding:0px 0px;">' . $value['title'] . '</td>';
539
-
540
- // If user has date, display that; otherwise placeholder
541
- $date_value = ( isset( $user_products[ $key ] ) && 1 != $user_products[ $key ] && 0 != $user_products[ $key ] && '' != $user_products[ $key ] ) ? date( 'Y-m-d', $user_products[ $key ] ) : "";
542
- $placeholder = ( ! isset( $user_products[ $key ] ) ) ? 'placeholder="' . __( 'Expiration date (optional)', 'wp-members' ) . '" ' : '';
543
- $product_date_field = ' <input type="text" name="_wpmem_membership_expiration_' . $key . '" value="' . $date_value . '" class="wpmem_datepicker" ' . $placeholder . ' />';
544
-
545
- if ( isset( $user_products[ $key ] ) ) {
546
- echo '<td align="center"><span id="wpmem_product_enabled" class="dashicons dashicons-yes"></span></td>';
547
- if ( $user_products[ $key ] != 1 ) {
548
- echo '<td>' . $product_date_field . '</td>';
549
- } else {
550
- echo '<td>&nbsp;</td>';
551
- }
552
- } else {
553
- if ( isset( $value['expires'] ) && ! empty( $value['expires'] ) ) {
554
- echo '<td><span id="wpmem_product_enabled" class="dashicons"></span></td>';
555
- echo '<td>' . $product_date_field . '</td>';
556
- } else {
557
- echo '<td>&nbsp;</td>';
558
- }
559
- }
560
- echo '</tr>';
561
- }
562
-
563
- ?></table>
564
- <script>
565
- jQuery(function() {
566
- jQuery( ".wpmem_datepicker" ).datepicker({
567
- dateFormat : "yy-mm-dd"
568
- });
569
- });
570
- </script>
571
- <?php
572
- }
573
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
574
  }
1
+ <?php
2
+ /**
3
+ * The WP_Members Products Admin Class.
4
+ *
5
+ * @package WP-Members
6
+ * @subpackage WP_Members_Products_Admin
7
+ * @since 3.2.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ exit();
13
+ }
14
+
15
+ class WP_Members_Products_Admin {
16
+
17
+ /**
18
+ * Class constructor.
19
+ *
20
+ * @since 3.2.0
21
+ *
22
+ * @global object $wpmem
23
+ */
24
+ function __construct() {
25
+ global $wpmem;
26
+ if ( 1 == $wpmem->enable_products ) {
27
+ add_filter( 'manage_wpmem_product_posts_columns', array( $this, 'columns_heading' ) );
28
+ add_action( 'manage_wpmem_product_posts_custom_column', array( $this, 'columns_content' ), 10, 2 );
29
+ add_action( 'add_meta_boxes', array( $this, 'meta_boxes' ) );
30
+ add_action( 'save_post', array( $this, 'save_details' ) );
31
+ add_action( 'wpmem_admin_after_block_meta', array( $this, 'add_product_to_post' ), 10, 2 );
32
+ add_action( 'wpmem_admin_block_meta_save', array( $this, 'save_product_to_post' ), 10, 3 );
33
+ add_action( 'admin_footer', array( $this, 'enqueue_select2' ) );
34
+ add_filter( 'manage_users_columns', array( $this, 'user_columns' ) );
35
+ add_filter( 'manage_users_custom_column', array( $this, 'user_columns_content' ), 10, 3 );
36
+ add_filter( 'manage_posts_columns', array( $this, 'post_columns' ) );
37
+ add_action( 'manage_posts_custom_column', array( $this, 'post_columns_content' ), 10, 2 );
38
+ add_filter( 'manage_pages_columns', array( $this, 'post_columns' ) );
39
+ add_action( 'manage_pages_custom_column', array( $this, 'post_columns_content' ), 10, 2 );
40
+ foreach( $wpmem->post_types as $key => $val ) {
41
+ add_filter( 'manage_' . $key . '_posts_columns', array( $this, 'post_columns' ) );
42
+ add_action( 'manage_' . $key . '_posts_custom_column', array( $this, 'post_columns_content' ), 10, 2 );
43
+ }
44
+
45
+ add_filter( 'wpmem_user_profile_tabs', array( $this, 'user_profile_tabs' ), 1 );
46
+ add_action( 'wpmem_user_profile_tabs_content', array( $this, 'user_profile_tab_content' ), 10 );
47
+ }
48
+
49
+ $this->default_products = $wpmem->membership->get_default_products();
50
+ }
51
+
52
+ /**
53
+ * Column headings for list table.
54
+ *
55
+ * @since 3.2.0
56
+ *
57
+ * @param array $columns
58
+ * @return array $columns
59
+ */
60
+ function columns_heading( $columns ) {
61
+ unset( $columns['date'] );
62
+ $columns['slug'] = __( 'Slug', 'wp-members' );
63
+ $columns['role'] = __( 'Role', 'wp-members' );
64
+ $columns['expires'] = __( 'Expires', 'wp-members' );
65
+ if ( $this->default_products ) {
66
+ $columns['default_products'] = __( 'Default', 'wp-members' );
67
+ }
68
+ $columns['last_updated'] = __( 'Last updated', 'wp-members' );
69
+ return $columns;
70
+ }
71
+
72
+ /**
73
+ * Column content for list table.
74
+ *
75
+ * @since 3.2.0
76
+ *
77
+ * @param string $column_name
78
+ * @param int $post_id
79
+ */
80
+ function columns_content( $column, $post_id ) {
81
+ $post = get_post( $post_id );
82
+ switch ( $column ) {
83
+ case 'slug':
84
+ echo $post->post_name;
85
+ break;
86
+ case 'role':
87
+ $role_slug = $this->get_meta( 'wpmem_product_role' );
88
+ if ( $role_slug ) {
89
+ $wp_roles = new WP_Roles;
90
+ $names = $wp_roles->get_names();
91
+
92
+ $role = $names[ $role_slug ] . ' (' . __( 'slug:', 'wp-members' ) . ' ' . $role_slug . ')';
93
+ echo esc_html( $role );
94
+ } else {
95
+ __( 'No role required', 'wp-members' );
96
+ }
97
+ break;
98
+ case 'expires':
99
+ $expires = $this->get_meta( 'wpmem_product_expires' );
100
+ $period = ( false !== $expires ) ? explode( "|", $expires[0] ) : __( 'Does not expire', 'wp-members' );
101
+ echo ( is_array( $period ) ) ? esc_html( $period[0] . ' ' . $period[1] ) : esc_html( $period );
102
+ break;
103
+ case 'default_products':
104
+ echo ( in_array( $post->post_name, $this->default_products ) ) ? __( 'Yes', 'wp-members' ) : '';
105
+ break;
106
+ case 'last_updated':
107
+ echo date_i18n( get_option( 'date_format' ), strtotime( esc_attr( $post->post_modified ) ) );
108
+ break;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Gets value of requested post meta.
114
+ *
115
+ * @since 3.2.0
116
+ *
117
+ * @param string $value
118
+ * @return string
119
+ */
120
+ function get_meta( $value ) {
121
+ global $post;
122
+ $field = get_post_meta( $post->ID, $value, true );
123
+ if ( ! empty( $field ) ) {
124
+ return is_array( $field ) ? stripslashes_deep( $field ) : stripslashes( wp_kses_decode_entities( $field ) );
125
+ } else {
126
+ return false;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Handles meta boxes for CPT editor.
132
+ *
133
+ * @since 3.2.0
134
+ * @since 3.3.4 Added message meta box.
135
+ */
136
+ function meta_boxes() {
137
+ remove_meta_box( 'slugdiv', 'wpmem_product', 'normal' );
138
+ add_meta_box(
139
+ 'membership_product',
140
+ __( 'Membership Product Details', 'wp-members' ),
141
+ array( $this, 'details_html' ),
142
+ 'wpmem_product',
143
+ 'normal',
144
+ 'high'
145
+ );
146
+ add_meta_box(
147
+ 'membership_product_message',
148
+ __( 'Membership Product Message (optional)', 'wp-members' ),
149
+ array( $this, 'message_meta_box_detail' ),
150
+ 'wpmem_product'
151
+ );
152
+ }
153
+
154
+ /**
155
+ * Gets an array of post types.
156
+ *
157
+ * @since 3.3.3
158
+ *
159
+ * @return array $post_types
160
+ */
161
+ function get_post_types() {
162
+ global $wpmem;
163
+ // @todo This comes from option tab. Should consider it being an api function.
164
+ $post_arr = array(
165
+ 'post' => __( 'Posts' ),
166
+ 'page' => __( 'Pages' ),
167
+ );
168
+ if ( ! empty( $wpmem->post_types ) ) {
169
+ foreach ( $wpmem->post_types as $key => $post_type ) {
170
+ $post_arr[ $key ] = $post_type;
171
+ }
172
+ }
173
+ return $post_arr;
174
+ }
175
+
176
+ /**
177
+ * Outputs HTML for CPT editor.
178
+ *
179
+ * @since 3.2.0
180
+ *
181
+ * @param object $post
182
+ */
183
+ function details_html( $post ) {
184
+
185
+ $product_default = $this->get_meta( 'wpmem_product_default' );
186
+ $product_expires = $this->get_meta( 'wpmem_product_expires' );
187
+ $product_role = $this->get_meta( 'wpmem_product_role' );
188
+ $product_no_gap = $this->get_meta( 'wpmem_product_no_gap' );
189
+ $product_fixed_period = $this->get_meta( 'wpmem_product_fixed_period' );
190
+
191
+ $product_expires = ( false !== $product_expires ) ? $product_expires[0] : $product_expires;
192
+
193
+ $periods = array( __( 'Period', 'wp-members' ) . '|', __( 'Day', 'wp-members' ) . '|day', __( 'Week', 'wp-members' ) . '|week', __( 'Month', 'wp-members' ) . '|month', __( 'Year', 'wp-members' ) . '|year' );
194
+ $show_role_detail = ( false !== $product_role ) ? 'show' : 'hide';
195
+ $show_exp_detail = ( false !== $product_expires ) ? 'show' : 'hide';
196
+ $show_exp_fixed = ( false !== $product_fixed_period ) ? 'show' : 'hide'; ?>
197
+
198
+ <?php wp_nonce_field( '_wpmem_product_nonce', 'wpmem_product_nonce' ); ?>
199
+ <h3><?php _e( 'Name (slug)', 'wp-members' ); ?></h3>
200
+ <p><strong><?php echo esc_attr( $post->post_name ); ?></strong></p>
201
+ <h3><?php esc_html_e( 'Optional Defaults', 'wp-members' ); ?></h3>
202
+ <p>
203
+ <input type="checkbox" name="wpmem_product_default" id="wpmem_product_default" value="1" <?php echo ( 1 == $product_default ) ? 'checked' : ''; ?> />
204
+ <label for="wpmem_product_default"><?php _e( 'Assign as default at registration? (optional)', 'wp-members' ); ?></label>
205
+ </p>
206
+ <p>
207
+ <?php
208
+
209
+ foreach( $this->get_post_types() as $key => $post_type ) {
210
+ echo '<div>';
211
+ echo '<input type="checkbox" name="wpmem_product_set_default_' . $key . '" id="wpmem_product_set_default_' . $key . '" value ="1" '; echo ( 1 == $this->get_meta( "wpmem_product_set_default_" . $key ) ) ? 'checked' : ''; echo ' />';
212
+ echo '<label for="wpmem_product_set_default_' . $key . '">' . sprintf( esc_html__( 'Pre-selected by default for new %s', 'wp-members' ), $post_type ) . '</label>';
213
+ echo '</div>';
214
+ }
215
+
216
+ ?>
217
+ </p>
218
+ <h3><?php esc_html_e( 'Optional Properties', 'wp-members' ); ?></h3>
219
+ <p>
220
+ <input type="checkbox" name="wpmem_product_role_required" id="wpmem_product_role_required" value="role-required" <?php echo ( false !== $product_role ) ? 'checked' : ''; ?> />
221
+ <label for="wpmem_product_role_required"><?php _e( 'Role Required? (optional)', 'wp-members' ); ?></label>
222
+ <label for="wpmem_product_role"></label>
223
+ <select name="wpmem_product_role" id="wpmem_product_role">
224
+ <option value=""><?php _e( 'No Role', 'wp-members' ); ?></option>
225
+ <?php wp_dropdown_roles( $this->get_meta( 'wpmem_product_role' ) ); ?>
226
+ </select>
227
+ </p>
228
+ <p>
229
+ <input type="checkbox" name="wpmem_product_expires" id="wpmem_product_expires" value="expires" <?php echo ( false !== $product_expires ) ? 'checked' : ''; ?> />
230
+ <label for="wpmem_product_expires"><?php _e( 'Expires (optional)', 'wp-members' ); ?></label>
231
+ <span id="wpmem_product_expires_wrap">
232
+ <label for="wpmem_product_number_of_periods" style="display:none;"><?php _e( 'Number', 'wp-members' ); ?></label>
233
+ <?php $period = explode( '|', $product_expires ); ?>
234
+ <input type="text" name="wpmem_product_number_of_periods" id="wpmem_product_number_of_periods" value="<?php echo esc_attr( $period[0] ); ?>" class="small-text" placeholder="<?php _e( 'Number', 'wp-members' ); ?>" style="width:66px;height:28px;vertical-align:middle;">
235
+ <label for="wpmem_product_time_period" style="display:none;"><?php _e( 'Period', 'wp-members' ); ?></label>
236
+ <?php echo wpmem_form_field( array( 'name'=>'wpmem_product_time_period', 'type'=>'select', 'value'=>$periods, 'compare'=>( ( isset( $period[1] ) ) ? $period[1] : '' ) ) ); ?>
237
+ <br />
238
+
239
+ <?php echo wpmem_form_field( array( 'name'=>'wpmem_product_no_gap', 'type'=>'checkbox', 'value'=>'1', 'compare'=>( ( isset( $product_no_gap ) ) && 1 == $product_no_gap ) ? $product_no_gap : '' ) ); ?>
240
+ <label for="wpmem_product_no_gap"><?php esc_html_e( 'Use "no gap" renewal', 'wp-members' ); ?></label>
241
+
242
+ <br />
243
+ <?php echo wpmem_form_field( array( 'name'=>'wpmem_product_fixed_period', 'type'=>'checkbox', 'value'=>'1', 'compare'=>( false != $product_fixed_period ) ? 1 : '' ) ); ?>
244
+ <label for="wpmem_product_fixed_period"><?php esc_html_e( 'Use a fixed period (such as Jan 1 - Dec 31, or Sept 1 - Aug 31)', 'wp-members' ); ?></label>
245
+ <br />
246
+ <span id="wpmem_product_fixed_period_select">
247
+ <style>.ui-datepicker-year {
248
+ display: none;
249
+ }</style>
250
+ <?php
251
+ if ( isset( $product_fixed_period ) ) {
252
+ $period_parts = ( isset( $product_fixed_period ) ) ? explode( "-", $product_fixed_period ) : false;
253
+ $period_start = ( $period_parts ) ? $period_parts[0] . '-' . $period_parts[1] : '';
254
+ $period_end = ( $period_parts ) ? $period_parts[2] . '-' . $period_parts[3] : '';
255
+ $period_grace_num = ( $period_parts && isset( $period_parts[4] ) ) ? $period_parts[4] : '';
256
+ $period_grace_per = ( $period_parts && isset( $period_parts[5] ) ) ? $period_parts[5] : '';
257
+ } else {
258
+ $period_start = $period_end = $period_grace_num = $period_grace_per = '';
259
+ }
260
+ ?>
261
+ <input type="text" class="datepicker" name="wpmem_product_fixed_period_start" value="<?php echo $period_start; ?>" placeholder="<?php esc_html_e( 'Period Start (dd-mm)', 'wp-members' ); ?>" />
262
+ <input type="text" class="datepicker" name="wpmem_product_fixed_period_end" value="<?php echo $period_end; ?>" placeholder="<?php esc_html_e( 'Period End (dd-mm)', 'wp-members' ); ?>" />
263
+ <script>
264
+ jQuery(function() {
265
+ jQuery( ".datepicker" ).datepicker({
266
+ minDate: new Date((new Date()).getFullYear(), 0, 1),
267
+ maxDate: new Date((new Date()).getFullYear(), 11, 31),
268
+ hideIfNoPrevNext: true,
269
+ dateFormat: 'dd-mm'
270
+ });
271
+ });
272
+ </script>
273
+ <br />
274
+ <label style="margin-left: 24px;"><?php esc_html_e( "Fixed period grace period", 'wp-members' ); ?></label>
275
+
276
+ <label for="wpmem_product_fixed_period_grace_number" style="display:none;"><?php esc_html_e( 'Number', 'wp-members' ); ?></label>
277
+ <?php $period = explode( '|', $product_expires ); ?>
278
+ <input type="text" name="wpmem_product_fixed_period_grace_number" id="wpmem_product_fixed_period_grace_number" value="<?php echo esc_attr( $period_grace_num ); ?>" class="small-text" placeholder="<?php _e( 'Number', 'wp-members' ); ?>" style="width:66px;margin-left:3px;">
279
+ <label for="wpmem_product_fixed_period_grace_period" style="display:none;"><?php _e( 'Period', 'wp-members' ); ?></label>
280
+ <?php echo wpmem_form_field( array( 'name'=>'wpmem_product_fixed_period_grace_period', 'type'=>'select', 'value'=>$periods, 'compare'=>( ( isset( $period_grace_per ) ) ? $period_grace_per : '' ) ) ); ?>
281
+ <br />
282
+
283
+ <span id="wpmem_product_fixed_period_explanation" style="margin-left: 24px;"><?php esc_html_e( "Point at which expiration date is for following time period. For example, if user who register August 1st would be part of the following year's Sept 1 - Aug 31 membership, set this at 1 Month. Leave blank for no grace period.", 'wp-members' ); ?></span>
284
+ </span>
285
+ </span>
286
+ </p>
287
+ <script>
288
+ (function($) {
289
+ $(document).ready(function() {
290
+ $("#wpmem_product_role").<?php echo ( $show_role_detail ); ?>();
291
+ $("#wpmem_product_expires_wrap").<?php echo ( $show_exp_detail ); ?>();
292
+ $("#wpmem_product_fixed_period_select").<?php echo ( $show_exp_fixed ); ?>();
293
+ });
294
+ $(document).ready(function() {
295
+ $('#wpmem_product_role_required').on('change', function (){
296
+ if ($(this).is(':checked')) {
297
+ $('#wpmem_product_role').show();
298
+ } else {
299
+ $('#wpmem_product_role').hide();
300
+ }
301
+ });
302
+ $('#wpmem_product_expires').on('change', function (){
303
+ if ($(this).is(':checked')) {
304
+ $('#wpmem_product_expires_wrap').show();
305
+ } else {
306
+ $('#wpmem_product_expires_wrap').hide();
307
+ }
308
+ });
309
+ $('#wpmem_product_fixed_period').on('change', function (){
310
+ if ($(this).is(':checked')) {
311
+ $('#wpmem_product_fixed_period_select').show();
312
+ } else {
313
+ $('#wpmem_product_fixed_period_select').hide();
314
+ }
315
+ });
316
+ });
317
+ })(jQuery);
318
+ </script><?php
319
+ }
320
+
321
+ /**
322
+ * Outputs HTML for CPT editor.
323
+ *
324
+ * @since 3.3.4
325
+ *
326
+ * @param object $post
327
+ */
328
+ function message_meta_box_detail( $post ) {
329
+ $product_message = get_post_meta( $post->ID, 'wpmem_product_message', true );
330
+ $message = ( $product_message ) ? $product_message : '';
331
+ echo '<label for="product_message">' . __( 'Restricted Message (displays when a user does not have access to a membership)', 'wp-members' ) . '</label>';
332
+ echo '<textarea name="product_message" id="product_message" rows="3" cols="50" id="" class="large-text code">' . $message . '</textarea>';
333
+ }
334
+
335
+ /**
336
+ * Saves meta fields for CPT
337
+ *
338
+ * @since 3.2.0
339
+ * @since 3.3.4 Added message meta.
340
+ *
341
+ * @param int $post_id
342
+ */
343
+ function save_details( $post_id ) {
344
+
345
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
346
+ if ( ! isset( $_POST['wpmem_product_nonce'] ) || ! wp_verify_nonce( $_POST['wpmem_product_nonce'], '_wpmem_product_nonce' ) ) return;
347
+ if ( ! current_user_can( 'edit_posts', $post_id ) ) return;
348
+
349
+ $post = get_post( $post_id );
350
+
351
+ $product_name = wpmem_get( 'wpmem_product_name', false );
352
+ $product_name = ( $product_name ) ? $product_name : $post->post_name;
353
+ update_post_meta( $post_id, 'wpmem_product_name', sanitize_text_field( $product_name ) );
354
+
355
+ $product_default = wpmem_get( 'wpmem_product_default', false );
356
+ update_post_meta( $post_id, 'wpmem_product_default', ( ( $product_default ) ? true : false ) );
357
+
358
+ $role_required = wpmem_get( 'wpmem_product_role_required', false );
359
+ if ( ! $role_required ) {
360
+ update_post_meta( $post_id, 'wpmem_product_role', false );
361
+ } else {
362
+ update_post_meta( $post_id, 'wpmem_product_role', sanitize_text_field( wpmem_get( 'wpmem_product_role' ) ) );
363
+ }
364
+
365
+ $expires = wpmem_get( 'wpmem_product_expires', false );
366
+ if ( ! $expires ) {
367
+ update_post_meta( $post_id, 'wpmem_product_expires', false );
368
+ } else {
369
+ $number = sanitize_text_field( wpmem_get( 'wpmem_product_number_of_periods' ) );
370
+ $period = sanitize_text_field( wpmem_get( 'wpmem_product_time_period' ) );
371
+ $no_gap = sanitize_text_field( wpmem_get( 'wpmem_product_no_gap' ) );
372
+ $expires_array = array( $number . "|" . $period );
373
+ update_post_meta( $post_id, 'wpmem_product_expires', $expires_array );
374
+ if ( $no_gap ) {
375
+ update_post_meta( $post_id, 'wpmem_product_no_gap', 1 );
376
+ } else {
377
+ delete_post_meta( $post_id, 'wpmem_product_no_gap' );
378
+ }
379
+
380
+ $fixed_period = sanitize_text_field( wpmem_get( 'wpmem_product_fixed_period' ) );
381
+ if ( $fixed_period ) {
382
+
383
+ // Start and end.
384
+ $period_start = wpmem_get( 'wpmem_product_fixed_period_start' );
385
+ $period_end = wpmem_get( 'wpmem_product_fixed_period_end' );
386
+
387
+ // Is there an entry grace period?
388
+ $grace_number = wpmem_get( 'wpmem_product_fixed_period_grace_number', false );
389
+ $grace_period = wpmem_get( 'wpmem_product_fixed_period_grace_period', false );
390
+ $save_fixed_period = $period_start . '-' . $period_end;
391
+ if ( $grace_number && $grace_period ) {
392
+ $save_fixed_period .= '-' . $grace_number . '-' . $grace_period;
393
+ }
394
+ update_post_meta( $post_id, 'wpmem_product_fixed_period', $save_fixed_period );
395
+ } else {
396
+ delete_post_meta( $post_id, 'wpmem_product_fixed_period' );
397
+ }
398
+ }
399
+
400
+ foreach( $this->get_post_types() as $key => $post_type ) {
401
+ if ( false !== wpmem_get( 'wpmem_product_set_default_' . $key, false ) ) {
402
+ update_post_meta( $post_id, 'wpmem_product_set_default_' . $key, 1 );
403
+ } else {
404
+ delete_post_meta( $post_id, 'wpmem_product_set_default_' . $key );
405
+ }
406
+ }
407
+
408
+ $product_message = wpmem_get( 'product_message', false );
409
+ if ( false !== $product_message && '' != $product_message ) {
410
+ update_post_meta( $post_id, 'wpmem_product_message', $product_message );
411
+ }
412
+ }
413
+
414
+ /**
415
+ * Add dropdown to post and page meta box for marking access by product..
416
+ *
417
+ * @since 3.2.0
418
+ * @since 3.3.3 Added defaults.
419
+ *
420
+ * @global object $pagenow
421
+ * @global object $wpmem
422
+ * @param object $post
423
+ * @param string $block
424
+ */
425
+ function add_product_to_post( $post, $block ) {
426
+ global $pagenow, $wpmem;
427
+
428
+ // For checking default memberships.
429
+ $is_new = ( 'post-new.php' == $pagenow ) ? true : false;
430
+
431
+ $product = $wpmem->membership->get_post_products( $post->ID ); //get_post_meta( $post->ID, $wpmem->membership->post_meta, true );
432
+ $product = ( $product ) ? $product : array();
433
+ $values[] = __( 'None', 'wp-members' ) . '|';
434
+
435
+ foreach ( $wpmem->membership->products as $key => $value ) {
436
+
437
+ if ( $is_new ) {
438
+ if ( isset( $value[ 'set_default_' . $post->post_type ] ) && 1 == $value[ 'set_default_' . $post->post_type ] ) {
439
+ $product[] = $key;
440
+ }
441
+ }
442
+
443
+ $values[] = $value['title'] . '|' . $key;
444
+ }
445
+
446
+ echo wpmem_form_label( array(
447
+ 'meta_key'=>$wpmem->membership->post_meta,
448
+ 'label'=>__( 'Limit access to:', 'wp-members' ),
449
+ 'type'=> 'multiselect'
450
+ ) );
451
+ echo "<br />";
452
+ echo wpmem_form_field( array(
453
+ 'name' => $wpmem->membership->post_meta,
454
+ 'type' => 'multiselect',
455
+ 'value' => $values,
456
+ 'compare' => $product,
457
+ 'class' => 'wpmem-product-select2',
458
+ ) );
459
+ }
460
+
461
+ /**
462
+ * Save custom post meta for access by product.
463
+ *
464
+ * @since 3.2.0
465
+ *
466
+ * @global object $wpmem
467
+ * @param object $post
468
+ */
469
+ function save_product_to_post( $post ) {
470
+ global $wpmem;
471
+ $products = wpmem_get( $wpmem->membership->post_meta );
472
+ $products = ( $products ) ? $products : array();
473
+ if ( empty( $products ) || ( 1 == count( $products ) && '' == $products[0] ) ) {
474
+ delete_post_meta( $post->ID, $wpmem->membership->post_meta );
475
+ } else {
476
+ update_post_meta( $post->ID, $wpmem->membership->post_meta, $products );
477
+ }
478
+ foreach ( $wpmem->membership->products as $key => $value ) {
479
+ if ( in_array( $key, $products ) ) {
480
+ update_post_meta( $post->ID, $wpmem->membership->post_stem . $key, 1 );
481
+ } else {
482
+ delete_post_meta( $post->ID, $wpmem->membership->post_stem . $key );
483
+ }
484
+ }
485
+ }
486
+
487
+ /**
488
+ * Enqueue select2 JS.
489
+ *
490
+ * @since 3.2.3
491
+ */
492
+ function enqueue_select2() {
493
+ $screen = get_current_screen();
494
+ if ( $screen->base == 'post' && $screen->parent_base == 'edit' ) { ?>
495
+ <script language="javascript">
496
+ (function($) {
497
+ $(document).ready(function() {
498
+ $('.wpmem-product-select2').select2();
499
+ });
500
+ })(jQuery);
501
+ </script><?php
502
+ }
503
+ }
504
+
505
+ /**
506
+ * Add membership product column to post table.
507
+ *
508
+ * @since 3.2.4
509
+ *
510
+ * @global object $wpmem
511
+ * @param array $columns
512
+ * @return array $columns
513
+ */
514
+ function post_columns( $columns ){
515
+ global $wpmem;
516
+ $post_type = ( isset( $_REQUEST['post_type'] ) ) ? sanitize_text_field( $_REQUEST['post_type'] ) : 'post';
517
+ if ( $post_type == 'page' || $post_type == 'post' || array_key_exists( $post_type, $wpmem->post_types ) ) {
518
+ $product = array( 'wpmem_product' => __( 'Required Membership', 'wp-members' ) );
519
+ $columns = wpmem_array_insert( $columns, $product, 'wpmem_block', 'before' );
520
+ }
521
+ return $columns;
522
+ }
523
+
524
+ /**
525
+ * Membership product column data.
526
+ *
527
+ * @since 3.2.4
528
+ *
529
+ * @global object $wpmem
530
+ * @param string $column_name
531
+ * @param int $post_id
532
+ */
533
+ function post_columns_content( $column_name, $post_id ) {
534
+ if ( 'wpmem_product' == $column_name ) {
535
+ global $wpmem;
536
+ $post_products = $wpmem->membership->get_post_products( $post_id );
537
+ if ( $post_products ) {
538
+ foreach ( $post_products as $meta ) {
539
+ if ( isset( $wpmem->membership->products[ $meta ]['title'] ) ) {
540
+ $display[] = $wpmem->membership->products[ $meta ]['title'];
541
+ }
542
+ }
543
+ echo implode( ", ", $display );
544
+ }
545
+ }
546
+ }
547
+
548
+ /**
549
+ * Add membership product column to post table.
550
+ *
551
+ * @since 3.2.4
552
+ *
553
+ * @param array $columns
554
+ * @return array $columns
555
+ */
556
+ function user_columns( $columns ){
557
+ $columns['wpmem_product'] = __( 'Membership', 'wp-members' );
558
+ return $columns;
559
+ }
560
+
561
+ /**
562
+ * Membership product column data.
563
+ *
564
+ * @since 3.2.4
565
+ *
566
+ * @global object $wpmem
567
+ * @param string $column_name
568
+ * @param int $post_id
569
+ * @return array $display
570
+ */
571
+ function user_columns_content( $val, $column_name, $user_id ) {
572
+ if ( 'wpmem_product' == $column_name ) {
573
+ global $wpmem;
574
+ $display = array();
575
+ $user_products = $wpmem->user->get_user_products( $user_id );
576
+ if ( $user_products ) {
577
+ foreach ( $user_products as $meta => $value ) {
578
+ if ( isset( $wpmem->membership->products[ $meta ]['title'] ) ) {
579
+ $display[] = $wpmem->membership->products[ $meta ]['title'];
580
+ }
581
+ }
582
+ }
583
+ return implode( ", ", $display );
584
+ }
585
+ return $val;
586
+ }
587
+
588
+ /**
589
+ * Creates tab for user profile.
590
+ *
591
+ * @since
592
+ *
593
+ * @param array $tabs
594
+ */
595
+ function user_profile_tabs( $tabs ) {
596
+ $tabs['memberships'] = array(
597
+ 'tab' => __( 'Memberships', 'wp-members' ),
598
+ );
599
+ return $tabs;
600
+ }
601
+
602
+ /**
603
+ * Add user product access to user profile.
604
+ *
605
+ * @since 3.2.0
606
+ *
607
+ * @global string $pagenow
608
+ * @global object $wpmem
609
+ * @param string $key
610
+ */
611
+ public function user_profile_tab_content( $key ) {
612
+ // If product enabled
613
+ if ( 'memberships' == $key ) {
614
+ global $pagenow, $wpmem;
615
+ /*
616
+ * If an admin is editing their provile, we need their ID,
617
+ * otherwise, it's the user_id param from the URL. It's a
618
+ * little more complicated than it sounds since you can't just
619
+ * check if the user is logged in, because the admin is always
620
+ * logged in when checking profiles.
621
+ */
622
+ $user_id = ( 'profile' == $pagenow && current_user_can( 'edit_users' ) ) ? get_current_user_id() : sanitize_text_field( wpmem_get( 'user_id', false, 'get' ) );
623
+ $user_products = $wpmem->user->get_user_products( $user_id );
624
+ echo '<h3>' . __( 'Product Access', 'wp-members' ) . '</h3>';
625
+ echo '<table>
626
+ <tr>
627
+ <th>' . __( 'Status', 'wp-members' ) . '</th>
628
+ <th>' . __( 'Membership', 'wp-members' ) . '</th>
629
+ <th>' . __( 'Enabled?', 'wp-members' ) . '</th>
630
+ <th>' . __( 'Expires', 'wp-members' ) . '</th>
631
+ </tr>'; ?>
632
+ <?php
633
+ foreach ( $wpmem->membership->products as $key => $value ) {
634
+ $checked = ( $user_products && array_key_exists( $key, $user_products ) ) ? "checked" : "";
635
+ echo "<tr>";
636
+ echo '<td style="padding:5px 5px;">
637
+ <select name="_wpmem_membership_product[' . $key . ']">
638
+ <option value="">----</option>
639
+ <option value="enable">' . __( 'Enable', 'wp-members' ) . '</option>
640
+ <option value="disable">' . __( 'Disable', 'wp-members' ) . '</option>
641
+ </select></td><td style="padding:0px 0px;">' . $value['title'] . '</td>';
642
+
643
+ // If user has date, display that; otherwise placeholder
644
+ $date_value = ( isset( $user_products[ $key ] ) && 1 != $user_products[ $key ] && 0 != $user_products[ $key ] && '' != $user_products[ $key ] ) ? date( 'Y-m-d', $user_products[ $key ] ) : "";
645
+ $placeholder = ( ! isset( $user_products[ $key ] ) ) ? 'placeholder="' . __( 'Expiration date (optional)', 'wp-members' ) . '" ' : '';
646
+ $product_date_field = ' <input type="text" name="_wpmem_membership_expiration_' . $key . '" value="' . $date_value . '" class="wpmem_datepicker" ' . $placeholder . ' />';
647
+
648
+ if ( isset( $user_products[ $key ] ) ) {
649
+ echo '<td align="center"><span id="wpmem_product_enabled" class="dashicons dashicons-yes"></span></td>';
650
+ if ( $user_products[ $key ] != 1 ) {
651
+ echo '<td>' . $product_date_field . '</td>';
652
+ } else {
653
+ echo '<td>&nbsp;</td>';
654
+ }
655
+ } else {
656
+ if ( isset( $value['expires'] ) && ! empty( $value['expires'] ) ) {
657
+ echo '<td><span id="wpmem_product_enabled" class="dashicons"></span></td>';
658
+ echo '<td>' . $product_date_field . '</td>';
659
+ } else {
660
+ echo '<td>&nbsp;</td>';
661
+ }
662
+ }
663
+ echo '</tr>';
664
+ }
665
+
666
+ ?></table>
667
+ <script>
668
+ jQuery(function() {
669
+ jQuery( ".wpmem_datepicker" ).datepicker({
670
+ dateFormat : "yy-mm-dd"
671
+ });
672
+ });
673
+ </script>
674
+ <?php
675
+ }
676
+ }
677
  }
includes/admin/tabs/class-wp-members-admin-tab-fields.php CHANGED
@@ -344,15 +344,15 @@ class WP_Members_Admin_Tab_Fields {
344
  } }
345
  } else {
346
  if (version_compare(PHP_VERSION, '5.3.0') >= 0) { ?>
347
- ---- Select One ----|,
348
- Choice One|choice_one,
349
- "1,000|one_thousand",
350
- "1,000-10,000|1,000-10,000",
351
- Last Row|last_row<?php } else { ?>
352
- ---- Select One ----|,
353
- Choice One|choice_one,
354
- Choice 2|choice_two,
355
- Last Row|last_row<?php } } ?></textarea>
356
  </li>
357
  <li>
358
  <label>&nbsp;</label>
344
  } }
345
  } else {
346
  if (version_compare(PHP_VERSION, '5.3.0') >= 0) { ?>
347
+ ---- Select One ----|,
348
+ Choice One|choice_one,
349
+ "1,000|one_thousand",
350
+ "1,000-10,000|1,000-10,000",
351
+ Last Row|last_row<?php } else { ?>
352
+ ---- Select One ----|,
353
+ Choice One|choice_one,
354
+ Choice 2|choice_two,
355
+ Last Row|last_row<?php } } ?></textarea>
356
  </li>
357
  <li>
358
  <label>&nbsp;</label>
includes/admin/tabs/class-wp-members-admin-tab-options.php CHANGED
@@ -291,6 +291,9 @@ class WP_Members_Admin_Tab_Options {
291
  <input type="hidden" name="wpmem_admin_a" value="update_cpts" />
292
  <td colspan="2"><?php submit_button( __( 'Update Settings', 'wp-members' ) ); ?></td>
293
  </tr>
 
 
 
294
  </table>
295
  </form>
296
  </div>
291
  <input type="hidden" name="wpmem_admin_a" value="update_cpts" />
292
  <td colspan="2"><?php submit_button( __( 'Update Settings', 'wp-members' ) ); ?></td>
293
  </tr>
294
+ <tr>
295
+ <td><?php _e( 'Please keep in mind that Custom Post Types are "custom" and therefore, not all of them will function exactly the same way. WP-Members will certainly work with any post type that operate like a post or a page; but you will need to review any custom post type added to determine that it functions the way you expect.', 'wp-members' ); ?></td>
296
+ </tr>
297
  </table>
298
  </form>
299
  </div>
includes/api/api-forms.php CHANGED
@@ -360,4 +360,171 @@ function wpmem_sanitize_field( $data, $type = 'text' ) {
360
  function wpmem_form_nonce( $nonce, $echo = false ) {
361
  $form = ( 'update' == $nonce || 'register' == $nonce ) ? 'longform' : 'shortform';
362
  return wp_nonce_field( 'wpmem_' . $form . '_nonce', '_wpmem_' . $nonce . '_nonce', true, $echo );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  }
360
  function wpmem_form_nonce( $nonce, $echo = false ) {
361
  $form = ( 'update' == $nonce || 'register' == $nonce ) ? 'longform' : 'shortform';
362
  return wp_nonce_field( 'wpmem_' . $form . '_nonce', '_wpmem_' . $nonce . '_nonce', true, $echo );
363
+ }
364
+
365
+ // @todo Experimental
366
+ /**
367
+ * Create WP-Members fields set for woo checkout.
368
+ *
369
+ * @since 3.3.4
370
+ *
371
+ * @param array $checkout_fields
372
+ */
373
+ function wpmem_woo_checkout_fields( $checkout_fields = false ) {
374
+ $woo_checkout = array(
375
+ 'billing_first_name',
376
+ 'billing_last_name',
377
+ 'billing_company',
378
+ 'billing_country',
379
+ 'billing_address_1',
380
+ 'billing_address_2',
381
+ 'billing_city',
382
+ 'billing_state',
383
+ 'billing_postcode',
384
+ 'billing_phone',
385
+ 'billing_email',
386
+ 'account_username',
387
+ 'account_password',
388
+ );
389
+ $fields = wpmem_fields();// echo '<pre>'; print_r( $fields ); echo '</pre>';
390
+
391
+ if ( ! $checkout_fields ) {
392
+ $checkout_fields = WC()->checkout()->checkout_fields;
393
+ }
394
+
395
+ foreach ( $fields as $meta_key => $field ) {
396
+
397
+ if ( 1 != $fields[ $meta_key ]['register'] ) {
398
+ unset( $fields[ $meta_key ] );
399
+ } else {
400
+ if ( isset( $checkout_fields['billing'][ $meta_key ] ) ) {
401
+ unset( $fields[ $meta_key ] );
402
+ }
403
+ if ( isset( $checkout_fields['shipping'][ $meta_key ] ) ) {
404
+ unset( $fields[ $meta_key ] );
405
+ }
406
+ if ( isset( $checkout_fields['account'][ $meta_key ] ) ) {
407
+ unset( $fields[ $meta_key ] );
408
+ }
409
+ if ( isset( $checkout_fields['order'][ $meta_key ] ) ) {
410
+ unset( $fields[ $meta_key ] );
411
+ }
412
+ }
413
+ }
414
+ unset( $fields['username'] );
415
+ unset( $fields['password'] );
416
+ unset( $fields['confirm_password'] );
417
+ unset( $fields['confirm_email'] );
418
+ unset( $fields['user_email'] );
419
+ unset( $fields['first_name'] );
420
+ unset( $fields['last_name'] );
421
+
422
+ return $fields;
423
+ }
424
+
425
+ /**
426
+ * Adds WP-Members custom fields to woo checkout.
427
+ *
428
+ * @since 3.3.4
429
+ *
430
+ * @param array $checkout_fields
431
+ */
432
+ function wpmem_woo_checkout_form( $checkout_fields ) {
433
+ global $wpmem;
434
+ $fields = wpmem_woo_checkout_fields( $checkout_fields );
435
+
436
+ foreach ( $fields as $meta_key => $field ) {
437
+ $checkout_fields['order'][ $meta_key ] = array(
438
+ 'type' => $fields[ $meta_key ]['type'],
439
+ 'label' => ( 'tos' == $meta_key ) ? $wpmem->forms->get_tos_link( $field, 'woo' ) : $fields[ $meta_key ]['label'],
440
+ 'required' => $fields[ $meta_key ]['required'],
441
+ );
442
+ if ( isset( $fields[ $meta_key ]['placeholder'] ) ) {
443
+ $checkout_fields['order'][ $meta_key ]['placeholder'] = $fields[ $meta_key ]['placeholder'];
444
+ }
445
+ }
446
+ return $checkout_fields;
447
+ }
448
+
449
+ /**
450
+ * Saves WP-Members custom fields for woo checkout.
451
+ *
452
+ * @since 3.3.4
453
+ *
454
+ * @param int $order_id
455
+ */
456
+ function wpmem_woo_checkout_update_meta( $order_id ) {
457
+
458
+ // Get user id from order.
459
+ $order = wc_get_order( $order_id );
460
+ $user_id = $order->get_user_id();
461
+
462
+ $checkout_fields = WC()->checkout()->checkout_fields;
463
+ $fields = wpmem_fields();
464
+ foreach ( $fields as $meta_key => $field ) {
465
+ if ( isset( $checkout_fields['order'][ $meta_key ] ) && isset( $_POST[ $meta_key ] ) ) {
466
+ switch ( $fields[ $meta_key ]['type'] ) {
467
+ case 'checkbox':
468
+ update_user_meta( $user_id, $meta_key, $field['checked_value'] );
469
+ break;
470
+ case 'textarea':
471
+ update_user_meta( $user_id, $meta_key, sanitize_textarea_field( $_POST[ $meta_key ] ) );
472
+ break;
473
+ case 'multicheckbox':
474
+ case 'multiselect':
475
+ update_user_meta( $user_id, $meta_key, wpmem_sanitize_array( $_POST[ $meta_key ] ) );
476
+ break;
477
+ default:
478
+ if ( 'user_url' == $meta_key ) {
479
+ wp_update_user( array( 'ID' => $user_id, 'user_url' => sanitize_text_field( $_POST[ $meta_key ] ) ) );
480
+ } else {
481
+ update_user_meta( $user_id, $meta_key, sanitize_text_field( $_POST[ $meta_key ] ) );
482
+ }
483
+ break;
484
+ }
485
+ }
486
+ }
487
+ }
488
+
489
+ function wpmem_form_field_wc_custom_field_types( $field, $key, $args, $value ) {
490
+
491
+ $wpmem_fields = wpmem_fields();
492
+ /**
493
+ * @type string $name (required) The field meta key.
494
+ * @type string $type (required) The field HTML type (url, email, image, file, checkbox, text, textarea, password, hidden, select, multiselect, multicheckbox, radio).
495
+ * @type string $value (optional) The field's value (can be a null value).
496
+ * @type string $compare (optional) Compare value.
497
+ * @type string $class (optional) Class identifier for the field.
498
+ * @type boolean $required (optional) If a value is required default: true).
499
+ * @type string $delimiter (optional) The field delimiter (pipe or comma, default: | ).
500
+ * @type string $placeholder (optional) Defines the placeholder attribute.
501
+ * @type string $pattern (optional) Adds a regex pattern to the field (HTML5).
502
+ * @type string $title (optional) Defines the title attribute.
503
+ * @type string $min (optional) Adds a min attribute (HTML5).
504
+ * @type string $max (optional) Adds a max attribute (HTML5).
505
+ * @type string $rows (optional) Adds rows attribute to textarea.
506
+ * @type string $cols (optional) Adds cols attribute to textarea.
507
+ */
508
+
509
+ // Let's only mess with WP-Members fields (in case another checkout fields plugin is used).
510
+ if ( array_key_exists( $key, $wpmem_fields ) ) {
511
+
512
+ $field_args = array(
513
+ 'name' => $key,
514
+ 'type' => $wpmem_fields[ $key ]['type'],
515
+ 'required' => $wpmem_fields[ $key ]['required'],
516
+ 'delimiter' => $wpmem_fields[ $key ]['delimiter'],
517
+ 'value' => $wpmem_fields[ $key ]['values'],
518
+ );
519
+
520
+ $field_html = wpmem_form_field( $field_args );
521
+ $field_html = str_replace( 'class="' . $wpmem_fields[ $key ]['type'] . '"', 'class="' . $wpmem_fields[ $key ]['type'] . '" style="display:initial;"', $field_html );
522
+ $field = '<p class="form-row ' . implode( ' ', $args['class'] ) .'" id="' . $key . '_field">
523
+ <label for="' . $key . '" class="' . implode( ' ', $args['label_class'] ) .'">' . $args['label'] . ( ( 1 == $wpmem_fields[ $key ]['required'] ) ? '&nbsp;<abbr class="required" title="required">*</abbr>' : '' ) . '</label>';
524
+ $field .= $field_html;
525
+ $field .= '</p>';
526
+
527
+ }
528
+
529
+ return $field;
530
  }
includes/api/api-users.php CHANGED
@@ -760,4 +760,27 @@ function wpmem_get_user_ip() {
760
  */
761
  return apply_filters( 'wpmem_get_ip', $ip );
762
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
763
  // End of file.
760
  */
761
  return apply_filters( 'wpmem_get_ip', $ip );
762
  }
763
+
764
+ /**
765
+ * Export all or selected users
766
+ *
767
+ * @since 2.9.7
768
+ * @since 3.2.0 Updated to use fputcsv.
769
+ * @since 3.2.1 Added user data filters.
770
+ * @since 3.3.0 Call object class static method.
771
+ * @since 3.3.4 Moved into general API.
772
+ *
773
+ * @todo Move object class file to main /includes/
774
+ *
775
+ * @global object $wpmem
776
+ *
777
+ * @param array $args
778
+ * @param array $users
779
+ */
780
+ function wpmem_export_users( $args, $users = null ) {
781
+ global $wpmem;
782
+ include_once( $wpmem->path . 'includes/admin/class-wp-members-export.php' );
783
+ WP_Members_Export::export_users( $args, $users );
784
+ }
785
+
786
  // End of file.
includes/class-wp-members-captcha.php CHANGED
@@ -16,6 +16,22 @@ if ( ! defined( 'ABSPATH' ) ) {
16
  }
17
 
18
  class WP_Members_Captcha {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  /**
21
  * Create reCAPTCHA form.
@@ -130,38 +146,60 @@ class WP_Members_Captcha {
130
  <img src="' . esc_url( $src ) . '" alt="captcha" width="' . esc_attr( $img_w ) . '" height="' . esc_attr( $img_h ) . '" />'
131
  );
132
  } else {
133
- return;
134
  }
135
  }
136
 
137
  /**
138
- * Process registration captcha.
139
  *
140
  * @since 3.1.6
141
  * @since 3.3.0 Ported from wpmem_register_handle_captcha() in register.php.
 
142
  *
143
  * @global $wpmem
144
  * @global $wpmem_themsg
 
145
  * @return $string
146
  */
147
- static function validate() {
148
 
149
  global $wpmem, $wpmem_themsg;
 
 
150
 
151
- // Get the captcha settings (api keys).
152
- $wpmem_captcha = get_option( 'wpmembers_captcha' );
153
 
154
- /*
155
- * @todo reCAPTCHA v1 is deprecated by Google. It is also no longer allowed
156
- * to be set for new installs of WP-Members. It is NOT compatible with
157
- * PHP 7.1 and is therefore fully obsolete.
158
- */
159
- // If captcha is on, check the captcha.
160
- if ( $wpmem->captcha == 1 && $wpmem_captcha['recaptcha'] ) {
161
- $wpmem->captcha = 3;
162
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
- if ( 2 == $wpmem->captcha ) {
165
  if ( defined( 'REALLYSIMPLECAPTCHA_VERSION' ) ) {
166
  // Validate Really Simple Captcha.
167
  $wpmem_captcha = new ReallySimpleCaptcha();
@@ -187,7 +225,7 @@ class WP_Members_Captcha {
187
 
188
  $privatekey = $wpmem_captcha['recaptcha']['private'];
189
 
190
- if ( 3 == $wpmem->captcha && $wpmem_captcha['recaptcha'] ) {
191
 
192
  $captcha = wpmem_get( 'g-recaptcha-response', false );
193
 
@@ -221,7 +259,7 @@ class WP_Members_Captcha {
221
  }
222
  return "empty";
223
  }
224
- } elseif ( 4 == $wpmem->captcha && $wpmem_captcha['recaptcha'] ) {
225
  $captcha = wpmem_get( 'recaptcha_response', false );
226
  if ( $_SERVER['REQUEST_METHOD'] === 'POST' && false !== $captcha ) {
227
 
@@ -246,6 +284,6 @@ class WP_Members_Captcha {
246
  }
247
  }
248
 
249
- return "passed_captcha";
250
  }
251
  }
16
  }
17
 
18
  class WP_Members_Captcha {
19
+
20
+ /**
21
+ * Display a CAPTCHA.
22
+ *
23
+ * @since 3.3.4
24
+ *
25
+ * @param string $type Type of captcha to display.
26
+ * @param array $keys Google reCAPTCHA keys (if used).
27
+ */
28
+ static function show( $type, $keys = false ) {
29
+ if ( 'rs_captcha' == $type ) {
30
+ return self::rs_captcha();
31
+ } else {
32
+ return self::recaptcha( $keys );
33
+ }
34
+ }
35
 
36
  /**
37
  * Create reCAPTCHA form.
146
  <img src="' . esc_url( $src ) . '" alt="captcha" width="' . esc_attr( $img_w ) . '" height="' . esc_attr( $img_h ) . '" />'
147
  );
148
  } else {
149
+ return "Really Simple CAPTCHA is not enabled";
150
  }
151
  }
152
 
153
  /**
154
+ * Process a captcha.
155
  *
156
  * @since 3.1.6
157
  * @since 3.3.0 Ported from wpmem_register_handle_captcha() in register.php.
158
+ * @since 3.3.4 Added argument to specify which captcha type to validate.
159
  *
160
  * @global $wpmem
161
  * @global $wpmem_themsg
162
+ * @param $which_captcha
163
  * @return $string
164
  */
165
+ static function validate( $which_captcha = false ) {
166
 
167
  global $wpmem, $wpmem_themsg;
168
+
169
+ if ( ! $which_captcha ) {
170
 
171
+ // Get the captcha settings (api keys).
172
+ $wpmem_captcha = get_option( 'wpmembers_captcha' );
173
 
174
+ /*
175
+ * @todo reCAPTCHA v1 is deprecated by Google. It is also no longer allowed
176
+ * to be set for new installs of WP-Members. It is NOT compatible with
177
+ * PHP 7.1 and is therefore fully obsolete.
178
+ */
179
+ // If captcha is on, check the captcha.
180
+ if ( $wpmem->captcha == 1 && $wpmem_captcha['recaptcha'] ) {
181
+ $wpmem->captcha = 3;
182
+ }
183
+
184
+ switch ( $wpmem->captcha ) {
185
+ case 1:
186
+ case 3:
187
+ $captcha = "recaptcha_v2";
188
+ break;
189
+ case 4:
190
+ $captcha = "recaptcha_v3";
191
+ break;
192
+ case 2:
193
+ default:
194
+ $captcha = "rs_captcha";
195
+ break;
196
+ }
197
+
198
+ } else {
199
+ $captcha = $which_captcha;
200
+ }
201
 
202
+ if ( 'rs_captcha' == $captcha ) {
203
  if ( defined( 'REALLYSIMPLECAPTCHA_VERSION' ) ) {
204
  // Validate Really Simple Captcha.
205
  $wpmem_captcha = new ReallySimpleCaptcha();
225
 
226
  $privatekey = $wpmem_captcha['recaptcha']['private'];
227
 
228
+ if ( 'recaptcha_v2' == $captcha && $wpmem_captcha['recaptcha'] ) {
229
 
230
  $captcha = wpmem_get( 'g-recaptcha-response', false );
231
 
259
  }
260
  return "empty";
261
  }
262
+ } elseif ( 'recaptcha_v3' == $captcha && $wpmem_captcha['recaptcha'] ) {
263
  $captcha = wpmem_get( 'recaptcha_response', false );
264
  if ( $_SERVER['REQUEST_METHOD'] === 'POST' && false !== $captcha ) {
265
 
284
  }
285
  }
286
 
287
+ return true;
288
  }
289
  }
includes/class-wp-members-forms.php CHANGED
@@ -72,7 +72,7 @@ class WP_Members_Forms {
72
  $placeholder = ( isset( $args['placeholder'] ) ) ? $args['placeholder'] : false;
73
  $pattern = ( isset( $args['pattern'] ) ) ? $args['pattern'] : false;
74
  $title = ( isset( $args['title'] ) ) ? $args['title'] : false;
75
- $file_types = ( isset( $args['file_types'] ) ) ? $args['file_types'] : false;
76
 
77
  // Handle field creation by type.
78
  switch ( $type ) {
@@ -129,7 +129,7 @@ class WP_Members_Forms {
129
  $accept = '';
130
  }
131
  $class = ( 'textbox' == $class ) ? "file" : $this->sanitize_class( $class );
132
- $str = "<input name=\"$name\" type=\"file\" id=\"$id\" value=\"" . esc_attr( $value ) . "\" class=\"$class\"$accept" . ( ( $required ) ? " required " : "" ) . ( ( 'image' == $file_type ) ? ' onchange="loadFile(event, this.id)"' : '' ) . ' />';
133
  break;
134
 
135
  case "checkbox":
@@ -162,7 +162,7 @@ class WP_Members_Forms {
162
  $pname = ( 'multiselect' == $type ) ? $name . "[]" : $name;
163
  $str = "<select name=\"$pname\" id=\"$id\" class=\"$class\"" . ( ( 'multiselect' == $type ) ? " multiple " : "" ) . ( ( $required ) ? " required " : "" ) . ">\n";
164
  if ( 'membership' == $type ) {
165
- $value = array( 'Choose membership|' );
166
  foreach( $wpmem->membership->products as $membership_key => $membership_value ) {
167
  $value[] = $membership_value['title'] . '|' . $membership_key;
168
  }
@@ -196,7 +196,7 @@ class WP_Members_Forms {
196
  $chk = ( isset( $pieces[2] ) && '' == $compare ) ? $pieces[1] : '';
197
  if ( isset( $pieces[1] ) && '' != $pieces[1] ) {
198
  $id_value = esc_attr( $id . '[' . $pieces[1] . ']' );
199
- $label = wpmem_form_label( array( 'meta_key'=>$id_value, 'label'=>esc_html( __( $pieces[0], 'wp-members' ) ), 'type'=>'radio', 'id'=>$id_value ) );
200
  $str = $str . $this->create_form_field( array(
201
  'id' => $id_value,
202
  'name' => $name . '[]',
@@ -1012,50 +1012,7 @@ class WP_Members_Forms {
1012
  ) );
1013
  $input = ( $field['required'] ) ? $input . $args['req_mark'] : $input;
1014
 
1015
- // Determine if TOS is a WP page or not.
1016
- $tos_content = stripslashes( get_option( 'wpmembers_tos' ) );
1017
- if ( has_shortcode( $tos_content, 'wpmem_tos' ) || has_shortcode( $tos_content, 'wp-members' ) ) {
1018
- $tos_link_url = do_shortcode( $tos_content );
1019
- $tos_link_tag = '<a href="' . esc_url( $tos_link_url ) . '" target="_blank">';
1020
- } else {
1021
- $tos_link_url = add_query_arg( 'tos', 'display' );
1022
- $tos_link_tag = "<a href=\"#\" onClick=\"window.open('" . $tos_link_url . "','tos');\">";
1023
- }
1024
-
1025
- /**
1026
- * Filter the TOS link.
1027
- *
1028
- * @since 3.2.6
1029
- *
1030
- * @param string $tos_link_tag
1031
- * @param string $tos_link_url
1032
- */
1033
- $tos_link_tag = apply_filters( 'wpmem_tos_link_tag', $tos_link_tag, $tos_link_url );
1034
-
1035
- /**
1036
- * Filter the TOS link text.
1037
- *
1038
- * @since 2.7.5
1039
- *
1040
- * @param string The link text.
1041
- * @param string $tag Toggle new registration or profile update. new|edit.
1042
- */
1043
- $tos_link_text = apply_filters( 'wpmem_tos_link_txt', $wpmem->get_text( 'register_tos' ), $tag );
1044
-
1045
- // If filtered value is not the default label, use that, otherwise use label.
1046
- // @note: if default changes, this check must change.
1047
- if ( __( 'Please indicate that you agree to the %s Terms of Service %s', 'wp-members' ) == $tos_link_text ) {
1048
- if ( __( 'TOS', 'wp-members' ) != $field['label'] && __( 'Terms of Service', 'wp-members' ) != $field['label'] ) {
1049
- $tos_link_text = $field['label'];
1050
- }
1051
- }
1052
-
1053
- // If tos string does not contain link identifiers (%s), wrap the whole string.
1054
- if ( ! strpos( $tos_link_text, '%s' ) ) {
1055
- $tos_link_text = '%s' . $tos_link_text . '%s';
1056
- }
1057
-
1058
- $input .= ' ' . sprintf( $tos_link_text, $tos_link_tag, '</a>' );
1059
 
1060
  // In previous versions, the div class would end up being the same as the row before.
1061
  $field_before = ( $args['wrap_inputs'] ) ? '<div class="div_text">' : '';
@@ -1366,7 +1323,7 @@ class WP_Members_Forms {
1366
  *
1367
  * @param string The default edit mode heading.
1368
  */
1369
- $heading = ( isset( $heading ) ) ? $headhing : apply_filters( 'wpmem_user_edit_heading', $wpmem->get_text( 'profile_heading' ) );
1370
  } else {
1371
  /**
1372
  * Filter the registration form heading.
@@ -1376,7 +1333,7 @@ class WP_Members_Forms {
1376
  * @param string $str
1377
  * @param string $tag Toggle new registration or profile update. new|edit.
1378
  */
1379
- $heading = ( isset( $heading ) ) ? $headhing : apply_filters( 'wpmem_register_heading', $wpmem->get_text( 'register_heading' ), $tag );
1380
  }
1381
  $form = $args['heading_before'] . $heading . $args['heading_after'] . $args['n'] . $form;
1382
 
@@ -1630,31 +1587,7 @@ class WP_Members_Forms {
1630
  if ( 'checkbox' == $field['type'] ) {
1631
 
1632
  if ( 'tos' == $meta_key ) {
1633
- $tos_content = stripslashes( get_option( 'wpmembers_tos' ) );
1634
- if ( has_shortcode( $tos_content, 'wpmem_tos' ) || has_shortcode( $tos_content, 'wp-members' ) ) {
1635
- $link = do_shortcode( $tos_content );
1636
- $tos_pop = '<a href="' . esc_url( $link ) . '" target="_blank">';
1637
- } else {
1638
- $tos_pop = "<a href=\"#\" onClick=\"window.open('" . $wpmem->url . "/wp-members-tos.php','mywindow');\">";
1639
- }
1640
- /** This filter is documented in includes/class-wp-members-forms.php */
1641
- $tos_link_text = apply_filters( 'wpmem_tos_link_txt', $wpmem->get_text( 'register_tos' ), 'new' );
1642
-
1643
- // If filtered value is not the default label, use that, otherwise use label.
1644
- // @note: if default changes, this check must change.
1645
- if ( __( 'Please indicate that you agree to the %s Terms of Service %s', 'wp-members' ) == $tos_link_text ) {
1646
- if ( __( 'TOS', 'wp-members' ) != $field['label'] && __( 'Terms of Service', 'wp-members' ) != $field['label'] ) {
1647
- $tos_link_text = $field['label'];
1648
- }
1649
- }
1650
-
1651
- // If tos string does not contain link identifiers (%s), wrap the whole string.
1652
- if ( ! strpos( $tos_link_text, '%s' ) ) {
1653
- $tos_link_text = '%s' . $tos_link_text . '%s';
1654
- }
1655
-
1656
- $tos_link_text = ' ' . sprintf( $tos_link_text, $tos_pop, '</a>' );
1657
-
1658
  }
1659
 
1660
  $label = ( 'tos' == $meta_key ) ? $tos_link_text : __( $field['label'], 'wp-members' );
@@ -1831,6 +1764,7 @@ class WP_Members_Forms {
1831
  case( 'multiselect' ):
1832
  case( 'multicheckbox' ):
1833
  case( 'radio' ):
 
1834
  $valtochk = ( isset( $_POST[ $meta_key ] ) ) ? sanitize_text_field( $_POST[ $meta_key ] ) : '';
1835
  $formfield_args = array(
1836
  'name' => $meta_key,
@@ -1850,7 +1784,8 @@ class WP_Members_Forms {
1850
  break;
1851
 
1852
  default:
1853
- echo '<input type="' . $field['type'] . '" name="' . $meta_key . '" id="' . $meta_key . '" class="input" value="'; echo ( isset( $_POST[ $meta_key ] ) ) ? esc_attr( $_POST[ $meta_key ] ) : ''; echo '" size="25" />';
 
1854
  break;
1855
  }
1856
 
@@ -2090,4 +2025,61 @@ class WP_Members_Forms {
2090
 
2091
  return wp_login_form( $args );
2092
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2093
  } // End of WP_Members_Forms class.
72
  $placeholder = ( isset( $args['placeholder'] ) ) ? $args['placeholder'] : false;
73
  $pattern = ( isset( $args['pattern'] ) ) ? $args['pattern'] : false;
74
  $title = ( isset( $args['title'] ) ) ? $args['title'] : false;
75
+ $file_types = ( isset( $args['file_types'] ) ) ? $args['file_types'] : false;
76
 
77
  // Handle field creation by type.
78
  switch ( $type ) {
129
  $accept = '';
130
  }
131
  $class = ( 'textbox' == $class ) ? "file" : $this->sanitize_class( $class );
132
+ $str = "<input name=\"$name\" type=\"file\" id=\"$id\" value=\"" . esc_attr( $value ) . "\" class=\"$class\"$accept" . ( ( $required ) ? " required " : "" ) . ( ( 'image' == $type ) ? ' onchange="loadFile(event, this.id)"' : '' ) . ' />';
133
  break;
134
 
135
  case "checkbox":
162
  $pname = ( 'multiselect' == $type ) ? $name . "[]" : $name;
163
  $str = "<select name=\"$pname\" id=\"$id\" class=\"$class\"" . ( ( 'multiselect' == $type ) ? " multiple " : "" ) . ( ( $required ) ? " required " : "" ) . ">\n";
164
  if ( 'membership' == $type ) {
165
+ $value = array( __( 'Choose membership', 'wp-members' ) . '|' );
166
  foreach( $wpmem->membership->products as $membership_key => $membership_value ) {
167
  $value[] = $membership_value['title'] . '|' . $membership_key;
168
  }
196
  $chk = ( isset( $pieces[2] ) && '' == $compare ) ? $pieces[1] : '';
197
  if ( isset( $pieces[1] ) && '' != $pieces[1] ) {
198
  $id_value = esc_attr( $id . '[' . $pieces[1] . ']' );
199
+ $label = wpmem_form_label( array( 'meta_key'=>$id_value, 'label'=>esc_html( __( $pieces[0], 'wp-members' ) ), 'type'=>'multicheckbox', 'id'=>$id_value ) );
200
  $str = $str . $this->create_form_field( array(
201
  'id' => $id_value,
202
  'name' => $name . '[]',
1012
  ) );
1013
  $input = ( $field['required'] ) ? $input . $args['req_mark'] : $input;
1014
 
1015
+ $input .= ' ' . $this->get_tos_link( $field, $tag );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1016
 
1017
  // In previous versions, the div class would end up being the same as the row before.
1018
  $field_before = ( $args['wrap_inputs'] ) ? '<div class="div_text">' : '';
1323
  *
1324
  * @param string The default edit mode heading.
1325
  */
1326
+ $heading = ( isset( $heading ) && '' != $heading ) ? $heading : apply_filters( 'wpmem_user_edit_heading', $wpmem->get_text( 'profile_heading' ) );
1327
  } else {
1328
  /**
1329
  * Filter the registration form heading.
1333
  * @param string $str
1334
  * @param string $tag Toggle new registration or profile update. new|edit.
1335
  */
1336
+ $heading = ( isset( $heading ) && '' != $heading ) ? $heading : apply_filters( 'wpmem_register_heading', $wpmem->get_text( 'register_heading' ), $tag );
1337
  }
1338
  $form = $args['heading_before'] . $heading . $args['heading_after'] . $args['n'] . $form;
1339
 
1587
  if ( 'checkbox' == $field['type'] ) {
1588
 
1589
  if ( 'tos' == $meta_key ) {
1590
+ $tos_link_text = $this->get_tos_link( $field, 'woo' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1591
  }
1592
 
1593
  $label = ( 'tos' == $meta_key ) ? $tos_link_text : __( $field['label'], 'wp-members' );
1764
  case( 'multiselect' ):
1765
  case( 'multicheckbox' ):
1766
  case( 'radio' ):
1767
+ case( 'membership' );
1768
  $valtochk = ( isset( $_POST[ $meta_key ] ) ) ? sanitize_text_field( $_POST[ $meta_key ] ) : '';
1769
  $formfield_args = array(
1770
  'name' => $meta_key,
1784
  break;
1785
 
1786
  default:
1787
+ $value = ( isset( $_POST[ $meta_key ] ) ) ? esc_attr( $_POST[ $meta_key ] ) : '';
1788
+ echo '<input type="' . $field['type'] . '" name="' . $meta_key . '" id="' . $meta_key . '" class="input" value="' . $value . '" size="25" />';
1789
  break;
1790
  }
1791
 
2025
 
2026
  return wp_login_form( $args );
2027
  }
2028
+
2029
+ /**
2030
+ * Generate TOS field with link.
2031
+ *
2032
+ * @since 3.3.5
2033
+ *
2034
+ * @param array $field
2035
+ * @param string $tag
2036
+ * @return string
2037
+ */
2038
+ function get_tos_link( $field, $tag = 'new' ) {
2039
+ global $wpmem;
2040
+ // Determine if TOS is a WP page or not.
2041
+ $tos_content = stripslashes( get_option( 'wpmembers_tos' ) );
2042
+ if ( has_shortcode( $tos_content, 'wpmem_tos' ) || has_shortcode( $tos_content, 'wp-members' ) ) {
2043
+ $tos_link_url = do_shortcode( $tos_content );
2044
+ $tos_link_tag = '<a href="' . esc_url( $tos_link_url ) . '" target="_blank">';
2045
+ } else {
2046
+ $tos_link_url = add_query_arg( 'tos', 'display' );
2047
+ $tos_link_tag = "<a href=\"#\" onClick=\"window.open('" . $tos_link_url . "','tos');\">";
2048
+ }
2049
+
2050
+ /**
2051
+ * Filter the TOS link.
2052
+ *
2053
+ * @since 3.2.6
2054
+ *
2055
+ * @param string $tos_link_tag
2056
+ * @param string $tos_link_url
2057
+ */
2058
+ $tos_link_tag = apply_filters( 'wpmem_tos_link_tag', $tos_link_tag, $tos_link_url );
2059
+
2060
+ /**
2061
+ * Filter the TOS link text.
2062
+ *
2063
+ * @since 2.7.5
2064
+ *
2065
+ * @param string The link text.
2066
+ * @param string $tag Toggle new registration or profile update. new|edit.
2067
+ */
2068
+ $tos_link_text = apply_filters( 'wpmem_tos_link_txt', $wpmem->get_text( 'register_tos' ), $tag );
2069
+
2070
+ // If filtered value is not the default label, use that, otherwise use label.
2071
+ // @note: if default changes, this check must change.
2072
+ if ( __( 'Please indicate that you agree to the %s Terms of Service %s', 'wp-members' ) == $tos_link_text ) {
2073
+ if ( __( 'TOS', 'wp-members' ) != $field['label'] && __( 'Terms of Service', 'wp-members' ) != $field['label'] ) {
2074
+ $tos_link_text = $field['label'];
2075
+ }
2076
+ }
2077
+
2078
+ // If tos string does not contain link identifiers (%s), wrap the whole string.
2079
+ if ( ! strpos( $tos_link_text, '%s' ) ) {
2080
+ $tos_link_text = '%s' . $tos_link_text . '%s';
2081
+ }
2082
+
2083
+ return sprintf( $tos_link_text, $tos_link_tag, '</a>' );
2084
+ }
2085
  } // End of WP_Members_Forms class.
includes/class-wp-members-products.php CHANGED
@@ -94,7 +94,9 @@ class WP_Members_Products {
94
 
95
  $this->load_products();
96
 
97
- add_filter( 'wpmem_securify', array( $this, 'product_access' ) );
 
 
98
  }
99
 
100
  /**
@@ -183,7 +185,7 @@ class WP_Members_Products {
183
 
184
  global $post, $wpmem;
185
  // Is the user logged in and is this blocked content?
186
- if ( is_user_logged_in() && wpmem_is_blocked() ) {
187
 
188
  // Get the post access products.
189
  $post_products = $this->get_post_products( $post->ID );
@@ -219,18 +221,24 @@ class WP_Members_Products {
219
  * Filter the product restricted message HTML.
220
  *
221
  * @since 3.3.3
 
222
  *
223
- * @param array $product_restricted {
224
  * $type string $wrapper_before
225
  * $type string $message
226
  * $type string $wrapper_after
227
  * }
 
 
 
 
 
228
  */
229
- $product_restricted = apply_filters( 'wpmem_product_restricted', array(
230
  'wrapper_before' => '<div class="wpmem_msg" align="center">',
231
  'message' => '<p>' . $message . '</p>',
232
  'wrapper_after' => '</div>',
233
- ) );
234
 
235
  $content = ( $access ) ? $content : $product_restricted['wrapper_before'] . $product_restricted['message'] . $product_restricted['wrapper_after'];
236
 
@@ -242,6 +250,34 @@ class WP_Members_Products {
242
  // Return unfiltered content for all other cases.
243
  return $content;
244
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
  /**
247
  * Register Membership Plans Custom Post Type
94
 
95
  $this->load_products();
96
 
97
+ add_filter( 'wpmem_securify', array( $this, 'product_access' ) );
98
+ add_filter( 'wpmem_product_restricted_msg', array( $this, 'access_message' ) );
99
+ add_filter( 'wpmem_restricted_msg', array( $this, 'access_message' ) );
100
  }
101
 
102
  /**
185
 
186
  global $post, $wpmem;
187
  // Is the user logged in and is this blocked content?
188
+ if ( ! is_admin() && is_user_logged_in() && wpmem_is_blocked() ) { // @todo Should is_admin() check be run on securify in general?
189
 
190
  // Get the post access products.
191
  $post_products = $this->get_post_products( $post->ID );
221
  * Filter the product restricted message HTML.
222
  *
223
  * @since 3.3.3
224
+ * @since 3.3.4 Added $post_products
225
  *
226
+ * @param array $product_restricted {
227
  * $type string $wrapper_before
228
  * $type string $message
229
  * $type string $wrapper_after
230
  * }
231
+ * @param array $post_products {
232
+ * Membership product slugs the post is restricted to.
233
+ *
234
+ * @type string $slug
235
+ * }
236
  */
237
+ $product_restricted = apply_filters( 'wpmem_product_restricted_args', array(
238
  'wrapper_before' => '<div class="wpmem_msg" align="center">',
239
  'message' => '<p>' . $message . '</p>',
240
  'wrapper_after' => '</div>',
241
+ ), $post_products );
242
 
243
  $content = ( $access ) ? $content : $product_restricted['wrapper_before'] . $product_restricted['message'] . $product_restricted['wrapper_after'];
244
 
250
  // Return unfiltered content for all other cases.
251
  return $content;
252
  }
253
+
254
+ /**
255
+ * Filters the access message if the user does not have
256
+ * access to this membership.
257
+ *
258
+ * @since 3.3.4
259
+ *
260
+ * @global stdClass $post
261
+ * @param string $msg
262
+ * @return string $msg
263
+ */
264
+ function access_message( $msg ) {
265
+ global $post;
266
+ $post_products = $this->get_post_products( $post->ID );
267
+ if ( $post_products ) {
268
+ foreach( $post_products as $post_product ) {
269
+ $membership_id = array_search( $post_product, $this->product_by_id );
270
+ $message = get_post_meta( $membership_id, 'wpmem_product_message', true );
271
+ if ( $message ) {
272
+ $product_message = ( isset( $product_message ) ) ? $product_message . '<p>' . $message . '</p>' : '<p>' . $message . '</p>';
273
+ }
274
+ }
275
+ if ( isset( $product_message ) ) {
276
+ $msg = $product_message;
277
+ }
278
+ }
279
+ return $msg;
280
+ }
281
 
282
  /**
283
  * Register Membership Plans Custom Post Type
includes/class-wp-members-shortcodes.php CHANGED
@@ -130,6 +130,13 @@ class WP_Members_Shortcodes {
130
  break;
131
 
132
  case in_array( 'register', $atts ):
 
 
 
 
 
 
 
133
  if ( is_user_logged_in() && '1' != $customizer ) {
134
  /*
135
  * If the user is logged in, return any nested content (if any)
@@ -139,7 +146,7 @@ class WP_Members_Shortcodes {
139
  } elseif ( is_user_logged_in() && is_customize_preview() && get_theme_mod( 'wpmem_show_form_message_dialog', false ) ) {
140
  $wpmem_themsg = __( "This is a generic message to display the form message dialog in the Customizer.", 'wp-members' );
141
  $content = wpmem_inc_regmessage( $wpmem->regchk, $wpmem_themsg );
142
- $content .= wpmem_register_form( 'new', $redirect_to );
143
  } else {
144
  if ( $wpmem->regchk == 'loginfailed' ) {
145
  $content = wpmem_inc_loginfailed() . wpmem_inc_login( 'login', $redirect_to );
@@ -151,7 +158,7 @@ class WP_Members_Shortcodes {
151
  $wpmem_themsg = __( 'There was an error with the CAPTCHA form.' ) . '<br /><br />' . $wpmem_captcha_err;
152
  }
153
  $content = ( $wpmem_themsg || $wpmem->regchk == 'success' ) ? wpmem_inc_regmessage( $wpmem->regchk, $wpmem_themsg ) : '';
154
- $content .= ( $wpmem->regchk == 'success' ) ? wpmem_inc_login( 'login', $redirect_to ) : wpmem_register_form( 'new', $redirect_to );
155
  }
156
  break;
157
 
@@ -306,8 +313,8 @@ class WP_Members_Shortcodes {
306
  } elseif ( true === $atts['msg'] || "true" === strtolower( $atts['msg'] ) ) {
307
  $do_return = true;
308
  $settings = array(
309
- 'wrapper_before' => '<div class="product_access_failed">',
310
- 'msg' => sprintf( __( 'Sorry, your account does not currently have access to %s content', 'wp-members' ), $wpmem->membership->products[ $membership ]['title'] ),
311
  'wrapper_after' => '</div>',
312
  );
313
  /**
@@ -458,7 +465,11 @@ class WP_Members_Shortcodes {
458
  break;
459
 
460
  case "renew":
461
- $content = wpmem_renew();
 
 
 
 
462
  break;
463
 
464
  default:
@@ -713,6 +724,7 @@ class WP_Members_Shortcodes {
713
  *
714
  * @since 3.1.2
715
  * @since 3.2.0 Moved to WP_Members_Shortcodes::tos().
 
716
  *
717
  * @param array $atts {
718
  * The shortcode attributes.
@@ -724,7 +736,8 @@ class WP_Members_Shortcodes {
724
  * @retrun string $content
725
  */
726
  function tos( $atts, $content, $tag ) {
727
- return esc_url( $atts['url'] );
 
728
  }
729
 
730
  /**
130
  break;
131
 
132
  case in_array( 'register', $atts ):
133
+
134
+ // Set up register form args.
135
+ $reg_form_args = array( 'tag' => 'new' );
136
+ if ( isset( $redirect_to ) ) {
137
+ $reg_form_args['redirect_to'] = $redirect_to;
138
+ }
139
+
140
  if ( is_user_logged_in() && '1' != $customizer ) {
141
  /*
142
  * If the user is logged in, return any nested content (if any)
146
  } elseif ( is_user_logged_in() && is_customize_preview() && get_theme_mod( 'wpmem_show_form_message_dialog', false ) ) {
147
  $wpmem_themsg = __( "This is a generic message to display the form message dialog in the Customizer.", 'wp-members' );
148
  $content = wpmem_inc_regmessage( $wpmem->regchk, $wpmem_themsg );
149
+ $content .= wpmem_register_form( $reg_form_args );
150
  } else {
151
  if ( $wpmem->regchk == 'loginfailed' ) {
152
  $content = wpmem_inc_loginfailed() . wpmem_inc_login( 'login', $redirect_to );
158
  $wpmem_themsg = __( 'There was an error with the CAPTCHA form.' ) . '<br /><br />' . $wpmem_captcha_err;
159
  }
160
  $content = ( $wpmem_themsg || $wpmem->regchk == 'success' ) ? wpmem_inc_regmessage( $wpmem->regchk, $wpmem_themsg ) : '';
161
+ $content .= ( $wpmem->regchk == 'success' ) ? wpmem_inc_login( 'login', $redirect_to ) : wpmem_register_form( $reg_form_args );
162
  }
163
  break;
164
 
313
  } elseif ( true === $atts['msg'] || "true" === strtolower( $atts['msg'] ) ) {
314
  $do_return = true;
315
  $settings = array(
316
+ 'wrapper_before' => '<div class="product_restricted_msg">',
317
+ 'msg' => sprintf( $wpmem->get_text( 'product_restricted' ), $wpmem->membership->products[ $membership ]['title'] ),
318
  'wrapper_after' => '</div>',
319
  );
320
  /**
465
  break;
466
 
467
  case "renew":
468
+ if ( function_exists( 'wpmem_renew' ) ) {
469
+ $content = wpmem_renew();
470
+ } else {
471
+ $content = '';
472
+ }
473
  break;
474
 
475
  default:
724
  *
725
  * @since 3.1.2
726
  * @since 3.2.0 Moved to WP_Members_Shortcodes::tos().
727
+ * @since 3.2.5 Now can use page slug (without full url).
728
  *
729
  * @param array $atts {
730
  * The shortcode attributes.
736
  * @retrun string $content
737
  */
738
  function tos( $atts, $content, $tag ) {
739
+ $url = ( strpos( $atts['url'], 'http' ) ) ? $atts['url'] : home_url( $atts['url'] );
740
+ return esc_url( $url );
741
  }
742
 
743
  /**
includes/class-wp-members-user-profile.php CHANGED
@@ -375,7 +375,7 @@ class WP_Members_User_Profile {
375
 
376
  if ( defined( 'WPMEM_EXP_MODULE' ) && $wpmem->use_exp == 1 ) {
377
  if ( function_exists( 'wpmem_a_extenduser' ) ) {
378
- wpmem_a_extend_user( $user_id );
379
  }
380
  }
381
 
@@ -501,8 +501,8 @@ class WP_Members_User_Profile {
501
  */
502
  if ( defined( 'WPMEM_EXP_MODULE' ) && $wpmem->use_exp == 1 ) {
503
  if ( ( $wpmem->mod_reg == 1 && get_user_meta( $user_id, 'active', true ) == 1 ) || ( $wpmem->mod_reg != 1 ) ) {
504
- if ( function_exists( 'wpmem_a_extenduser' ) ) {
505
- wpmem_a_extenduser( $user_id );
506
  }
507
  }
508
  }
375
 
376
  if ( defined( 'WPMEM_EXP_MODULE' ) && $wpmem->use_exp == 1 ) {
377
  if ( function_exists( 'wpmem_a_extenduser' ) ) {
378
+ wpmem_a_extenduser( $user_id );
379
  }
380
  }
381
 
501
  */
502
  if ( defined( 'WPMEM_EXP_MODULE' ) && $wpmem->use_exp == 1 ) {
503
  if ( ( $wpmem->mod_reg == 1 && get_user_meta( $user_id, 'active', true ) == 1 ) || ( $wpmem->mod_reg != 1 ) ) {
504
+ if ( function_exists( 'wpmem_a_extend_user' ) ) {
505
+ wpmem_a_extend_user( $user_id );
506
  }
507
  }
508
  }
includes/class-wp-members-user.php CHANGED
@@ -172,8 +172,10 @@ class WP_Members_User {
172
  $this->reg_type['is_native'] = ( __( 'Register' ) == wpmem_get( 'wp-submit' ) ) ? true : false;
173
  // Is this a Users > Add New process? Checks the post action.
174
  $this->reg_type['is_add_new'] = ( 'createuser' == wpmem_get( 'action' ) ) ? true : false;
175
- // Is this a WooCommerce checkout registration? Checks for WC fields.
176
- $this->reg_type['is_woo'] = ( wpmem_get( 'woocommerce_checkout_place_order' ) || wpmem_get( 'woocommerce-register-nonce' ) ) ? true : false;
 
 
177
  }
178
 
179
  /**
@@ -345,7 +347,7 @@ class WP_Members_User {
345
  // Process CAPTCHA.
346
  if ( 0 != $wpmem->captcha ) {
347
  $check_captcha = WP_Members_Captcha::validate();
348
- if ( 'passed_captcha' != $check_captcha ) {
349
  return $check_captcha;
350
  }
351
  }
172
  $this->reg_type['is_native'] = ( __( 'Register' ) == wpmem_get( 'wp-submit' ) ) ? true : false;
173
  // Is this a Users > Add New process? Checks the post action.
174
  $this->reg_type['is_add_new'] = ( 'createuser' == wpmem_get( 'action' ) ) ? true : false;
175
+ // Is this a WooCommerce my account registration? Checks for WC fields.
176
+ $this->reg_type['is_woo'] = ( wpmem_get( 'woocommerce-register-nonce' ) ) ? true : false;
177
+ // Is this a WooCommerce checkout?
178
+ $this->reg_type['is_woo_checkout'] = ( wpmem_get( 'woocommerce_checkout_place_order' ) ) ? true : false;
179
  }
180
 
181
  /**
347
  // Process CAPTCHA.
348
  if ( 0 != $wpmem->captcha ) {
349
  $check_captcha = WP_Members_Captcha::validate();
350
+ if ( true != $check_captcha ) {
351
  return $check_captcha;
352
  }
353
  }
includes/class-wp-members.php CHANGED
@@ -419,7 +419,7 @@ class WP_Members {
419
  add_action( 'login_enqueue_scripts', array( $this, 'enqueue_style_wp_login' ) ); // styles the native registration
420
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) ); // Enqueues the stylesheet.
421
  add_action( 'wp_enqueue_scripts', array( $this, 'loginout_script' ) );
422
- add_action( 'pre_get_posts', array( $this, 'do_hide_posts' ) );
423
  add_action( 'customize_register', array( $this, 'customizer_settings' ) );
424
  add_action( 'admin_menu', 'wpmem_admin_options' ); // adds admin menu
425
 
@@ -428,8 +428,16 @@ class WP_Members {
428
  add_action( 'wpmem_pwd_change', array( $this->user, 'set_as_logged_in' ), 10 );
429
  }
430
 
431
- add_filter( 'register_form', 'wpmem_wp_register_form' ); // adds fields to the default wp registration
432
- add_action( 'woocommerce_register_form', 'wpmem_woo_register_form' );
 
 
 
 
 
 
 
 
433
 
434
  // Add filters.
435
  add_filter( 'the_content', array( $this, 'do_securify' ), 99 );
@@ -1144,7 +1152,14 @@ class WP_Members {
1144
  }
1145
  }
1146
  }
1147
- return $hidden;
 
 
 
 
 
 
 
1148
  }
1149
 
1150
  /**
@@ -1158,7 +1173,17 @@ class WP_Members {
1158
  function do_hide_posts( $query ) {
1159
  $hidden_posts = $this->get_hidden_posts();
1160
  if ( ! empty( $hidden_posts ) ) {
1161
- $query->set( 'post__not_in', $hidden_posts );
 
 
 
 
 
 
 
 
 
 
1162
  }
1163
  return $query;
1164
  }
419
  add_action( 'login_enqueue_scripts', array( $this, 'enqueue_style_wp_login' ) ); // styles the native registration
420
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) ); // Enqueues the stylesheet.
421
  add_action( 'wp_enqueue_scripts', array( $this, 'loginout_script' ) );
422
+ add_action( 'pre_get_posts', array( $this, 'do_hide_posts' ), 20 );
423
  add_action( 'customize_register', array( $this, 'customizer_settings' ) );
424
  add_action( 'admin_menu', 'wpmem_admin_options' ); // adds admin menu
425
 
428
  add_action( 'wpmem_pwd_change', array( $this->user, 'set_as_logged_in' ), 10 );
429
  }
430
 
431
+ add_filter( 'register_form', 'wpmem_wp_register_form' ); // adds fields to the default wp registration
432
+ add_action( 'woocommerce_register_form', 'wpmem_woo_register_form' );
433
+
434
+ add_action( 'woocommerce_checkout_update_order_meta', 'wpmem_woo_checkout_update_meta' );
435
+ add_action( 'woocommerce_form_field_multicheckbox', 'wpmem_form_field_wc_custom_field_types', 10, 4 );
436
+ add_action( 'woocommerce_form_field_multiselect', 'wpmem_form_field_wc_custom_field_types', 10, 4 );
437
+ add_action( 'woocommerce_form_field_radio', 'wpmem_form_field_wc_custom_field_types', 10, 4 );
438
+ if ( ! is_user_logged_in() ) {
439
+ add_filter( 'woocommerce_checkout_fields', 'wpmem_woo_checkout_form' );
440
+ }
441
 
442
  // Add filters.
443
  add_filter( 'the_content', array( $this, 'do_securify' ), 99 );
1152
  }
1153
  }
1154
  }
1155
+ /**
1156
+ * Filter the hidden posts array.
1157
+ *
1158
+ * @since 3.3.4
1159
+ *
1160
+ * @param array $hidden
1161
+ */
1162
+ return apply_filters( 'wpmem_hidden_posts', $hidden );
1163
  }
1164
 
1165
  /**
1173
  function do_hide_posts( $query ) {
1174
  $hidden_posts = $this->get_hidden_posts();
1175
  if ( ! empty( $hidden_posts ) ) {
1176
+ // Add hidden posts to post__not_in while maintaining any existing exclusions.
1177
+ $post__not_in = array_merge( $query->query_vars['post__not_in'], $hidden_posts );
1178
+ /**
1179
+ * Filter post__not_in.
1180
+ *
1181
+ * @since 3.3.4
1182
+ *
1183
+ * @param array $post__not_in
1184
+ */
1185
+ $post__not_in = apply_filters( 'wpmem_post__not_in', $post__not_in );
1186
+ $query->set( 'post__not_in', $post__not_in );
1187
  }
1188
  return $query;
1189
  }
includes/walkers/class-wp-members-walker-nav-menu.php CHANGED
@@ -1,231 +1,241 @@
1
- <?php
2
- /**
3
- * Navigation Menu API: (Modifed) Walker_Nav_Menu_Edit class
4
- *
5
- * Create HTML list of nav menu input items.
6
- *
7
- * @package WP_Members
8
- * @since 3.3.0
9
- * @uses Walker_Nav_Menu
10
- */
11
-
12
- class WP_Members_Walker_Nav_Menu extends Walker_Nav_Menu {
13
- /**
14
- * Starts the list before the elements are added.
15
- *
16
- * @see Walker_Nav_Menu::start_lvl()
17
- *
18
- * @since 3.0.0
19
- *
20
- * @param string $output Passed by reference.
21
- * @param int $depth Depth of menu item. Used for padding.
22
- * @param array $args Not used.
23
- */
24
- public function start_lvl( &$output, $depth = 0, $args = array() ) {}
25
-
26
- /**
27
- * Ends the list of after the elements are added.
28
- *
29
- * @see Walker_Nav_Menu::end_lvl()
30
- *
31
- * @since 3.0.0
32
- *
33
- * @param string $output Passed by reference.
34
- * @param int $depth Depth of menu item. Used for padding.
35
- * @param array $args Not used.
36
- */
37
- public function end_lvl( &$output, $depth = 0, $args = array() ) {}
38
-
39
- /**
40
- * Start the element output.
41
- *
42
- * @see Walker_Nav_Menu::start_el()
43
- * @since 3.0.0
44
- *
45
- * @global int $_wp_nav_menu_max_depth
46
- *
47
- * @param string $output Passed by reference. Used to append additional content.
48
- * @param object $item Menu item data object.
49
- * @param int $depth Depth of menu item. Used for padding.
50
- * @param array $args Not used.
51
- * @param int $id Not used.
52
- */
53
- public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
54
- global $_wp_nav_menu_max_depth;
55
-
56
- $_wp_nav_menu_max_depth = $depth > $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth;
57
-
58
- $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
59
-
60
- ob_start();
61
- $item_id = esc_attr( $item->ID );
62
- $removed_args = array(
63
- 'action',
64
- 'customlink-tab',
65
- 'edit-menu-item',
66
- 'menu-item',
67
- 'page-tab',
68
- '_wpnonce',
69
- );
70
-
71
- $original_title = '';
72
- if ( 'taxonomy' == $item->type ) {
73
- $original_title = get_term_field( 'name', $item->object_id, $item->object, 'raw' );
74
- if ( is_wp_error( $original_title ) )
75
- $original_title = false;
76
- } elseif ( 'post_type' == $item->type ) {
77
- $original_object = get_post( $item->object_id );
78
- $original_title = $original_object->post_title;
79
- }
80
-
81
- $classes = array(
82
- 'menu-item menu-item-depth-' . $depth,
83
- 'menu-item-' . esc_attr( $item->object ),
84
- 'menu-item-edit-' . ( ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? 'active' : 'inactive'),
85
- );
86
-
87
- $title = $item->title;
88
-
89
- if ( ! empty( $item->_invalid ) ) {
90
- $classes[] = 'menu-item-invalid';
91
- /* translators: %s: title of menu item which is invalid */
92
- $title = sprintf( esc_html__( '%s (Invalid)', 'wp-members' ), $item->title );
93
- } elseif ( isset( $item->post_status ) && 'draft' == $item->post_status ) {
94
- $classes[] = 'pending';
95
- /* translators: %s: title of menu item in draft status */
96
- $title = sprintf( esc_html__( '%s (Pending)', 'wp-members'), $item->title );
97
- }
98
-
99
- $title = empty( $item->label ) ? $title : $item->label;
100
-
101
- ?>
102
- <li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>">
103
- <div class="menu-item-bar">
104
- <div class="menu-item-handle ui-sortable-handle">
105
- <span class="item-title">
106
- <span class="menu-item-title"><?php echo esc_html( $title ); ?></span>
107
- <span class="is-submenu" style="display: none;">sub item</span>
108
- </span>
109
- <span class="item-controls">
110
- <span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
111
- <span class="item-order hide-if-js">
112
- <a href="<?php
113
- echo wp_nonce_url(
114
- add_query_arg(
115
- array(
116
- 'action' => 'move-up-menu-item',
117
- 'menu-item' => $item_id,
118
- ),
119
- remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
120
- ),
121
- 'move-menu_item'
122
- );
123
- ?>" class="item-move-up" aria-label="<?php esc_attr_e( 'Move up', 'wp-members' ); ?>">&#8593;</a>
124
- |
125
- <a href="<?php
126
- echo wp_nonce_url(
127
- add_query_arg(
128
- array(
129
- 'action' => 'move-down-menu-item',
130
- 'menu-item' => $item_id,
131
- ),
132
- remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
133
- ),
134
- 'move-menu_item'
135
- );
136
- ?>" class="item-move-down" aria-label="<?php esc_attr_e( 'Move down', 'wp-members' ); ?>">&#8595;</a>
137
- </span>
138
- <a class="item-edit" id="edit-<?php echo $item_id; ?>" title="<?php esc_attr_e( 'Edit Menu Item', 'wp-members' ); ?>" href="<?php
139
- echo ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? admin_url( 'nav-menus.php' ) : add_query_arg( 'edit-menu-item', $item_id, remove_query_arg( $removed_args, admin_url( 'nav-menus.php#menu-item-settings-' . $item_id ) ) );
140
- ?>"><span class="screen-reader-text"><?php esc_html_e( 'Edit', 'wp-members' ); ?></span></a>
141
- </span>
142
- </div>
143
- </div>
144
-
145
- <div class="menu-item-settings wp-clearfix" id="menu-item-settings-<?php echo $item_id; ?>">
146
- <?php if( 'custom' == $item->type ) : ?>
147
- <p class="field-url description description-wide">
148
- <label for="edit-menu-item-url-<?php echo $item_id; ?>">
149
- <?php _e( 'URL' ); ?><br />
150
- <input type="text" id="edit-menu-item-url-<?php echo $item_id; ?>" class="widefat code edit-menu-item-url" name="menu-item-url[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->url ); ?>" />
151
- </label>
152
- </p>
153
- <?php endif; ?>
154
- <p class="description description-thin">
155
- <label for="edit-menu-item-title-<?php echo $item_id; ?>">
156
- <?php _e( 'Navigation Label' ); ?><br />
157
- <input type="text" id="edit-menu-item-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-title" name="menu-item-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->title ); ?>" />
158
- </label>
159
- </p>
160
- <p class="description description-thin">
161
- <label for="edit-menu-item-attr-title-<?php echo $item_id; ?>">
162
- <?php _e( 'Title Attribute' ); ?><br />
163
- <input type="text" id="edit-menu-item-attr-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-attr-title" name="menu-item-attr-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->post_excerpt ); ?>" />
164
- </label>
165
- </p>
166
- <p class="field-link-target description">
167
- <label for="edit-menu-item-target-<?php echo $item_id; ?>">
168
- <input type="checkbox" id="edit-menu-item-target-<?php echo $item_id; ?>" value="_blank" name="menu-item-target[<?php echo $item_id; ?>]"<?php checked( $item->target, '_blank' ); ?> />
169
- <?php _e( 'Open link in a new window/tab' ); ?>
170
- </label>
171
- </p>
172
- <p class="field-css-classes description description-thin">
173
- <label for="edit-menu-item-classes-<?php echo $item_id; ?>">
174
- <?php _e( 'CSS Classes (optional)' ); ?><br />
175
- <input type="text" id="edit-menu-item-classes-<?php echo $item_id; ?>" class="widefat code edit-menu-item-classes" name="menu-item-classes[<?php echo $item_id; ?>]" value="<?php echo esc_attr( implode(' ', $item->classes ) ); ?>" />
176
- </label>
177
- </p>
178
- <p class="field-xfn description description-thin">
179
- <label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
180
- <?php _e( 'Link Relationship (XFN)' ); ?><br />
181
- <input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>" class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->xfn ); ?>" />
182
- </label>
183
- </p>
184
- <p class="field-description description description-wide">
185
- <label for="edit-menu-item-description-<?php echo $item_id; ?>">
186
- <?php _e( 'Description' ); ?><br />
187
- <textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
188
- <span class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>
189
- </label>
190
- </p>
191
- <?php
192
- // This is the added section
193
- // do_action( 'wpmem_nav_menu_item_options', $item_id, $item, $depth, $args );
194
- do_action( 'wp_nav_menu_item_custom_fields', $item_id, $item, $depth, $args, $id );
195
- // end added section
196
- ?>
197
- <div class="menu-item-actions description-wide submitbox">
198
- <?php if( 'custom' != $item->type && $original_title !== false ) : ?>
199
- <p class="link-to-original">
200
- <?php printf( esc_html__( 'Original: %s' ), '<a href="' . esc_attr( $item->url ) . '">' . esc_html( $original_title ) . '</a>' ); ?>
201
- </p>
202
- <?php endif; ?>
203
- <a class="item-delete submitdelete deletion" id="delete-<?php echo esc_attr( $item_id ); ?>" href="<?php
204
- echo wp_nonce_url(
205
- add_query_arg(
206
- array(
207
- 'action' => 'delete-menu-item',
208
- 'menu-item' => $item_id,
209
- ),
210
- remove_query_arg( $removed_args, admin_url( 'nav-menus.php' ) )
211
- ),
212
- 'delete-menu_item_' . esc_attr( $item_id )
213
- ); ?>"><?php _e('Remove'); ?></a> <span class="meta-sep"> | </span> <a class="item-cancel submitcancel" id="cancel-<?php echo $item_id; ?>" href="<?php echo esc_url( add_query_arg( array('edit-menu-item' => $item_id, 'cancel' => time()), remove_query_arg( $removed_args, admin_url( 'nav-menus.php' ) ) ) );
214
- ?>#menu-item-settings-<?php echo $item_id; ?>"><?php _e('Cancel'); ?></a>
215
- </div>
216
-
217
- <input class="menu-item-data-db-id" type="hidden" name="menu-item-db-id[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo $item_id; ?>" />
218
- <input class="menu-item-data-object-id" type="hidden" name="menu-item-object-id[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->object_id ); ?>" />
219
- <input class="menu-item-data-object" type="hidden" name="menu-item-object[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->object ); ?>" />
220
- <input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->menu_item_parent ); ?>" />
221
- <input class="menu-item-data-position" type="hidden" name="menu-item-position[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->menu_order ); ?>" />
222
- <input class="menu-item-data-type" type="hidden" name="menu-item-type[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->type ); ?>" />
223
- </div><!-- .menu-item-settings-->
224
- <ul class="menu-item-transport"></ul>
225
- <?php
226
-
227
- $output .= ob_get_clean();
228
-
229
- }
230
-
231
- } // Walker_Nav_Menu_Edit
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Navigation Menu API: (Modifed) Walker_Nav_Menu_Edit class
4
+ *
5
+ * Create HTML list of nav menu input items.
6
+ *
7
+ * @package WP_Members
8
+ * @since 3.3.0
9
+ * @uses Walker_Nav_Menu
10
+ */
11
+
12
+ class WP_Members_Walker_Nav_Menu extends Walker_Nav_Menu {
13
+ /**
14
+ * Starts the list before the elements are added.
15
+ *
16
+ * @see Walker_Nav_Menu::start_lvl()
17
+ *
18
+ * @since 3.0.0
19
+ *
20
+ * @param string $output Passed by reference.
21
+ * @param int $depth Depth of menu item. Used for padding.
22
+ * @param array $args Not used.
23
+ */
24
+ public function start_lvl( &$output, $depth = 0, $args = array() ) {}
25
+
26
+ /**
27
+ * Ends the list of after the elements are added.
28
+ *
29
+ * @see Walker_Nav_Menu::end_lvl()
30
+ *
31
+ * @since 3.0.0
32
+ *
33
+ * @param string $output Passed by reference.
34
+ * @param int $depth Depth of menu item. Used for padding.
35
+ * @param array $args Not used.
36
+ */
37
+ public function end_lvl( &$output, $depth = 0, $args = array() ) {}
38
+
39
+ /**
40
+ * Start the element output.
41
+ *
42
+ * @see Walker_Nav_Menu::start_el()
43
+ * @since 3.0.0
44
+ *
45
+ * @global int $_wp_nav_menu_max_depth
46
+ *
47
+ * @param string $output Passed by reference. Used to append additional content.
48
+ * @param object $item Menu item data object.
49
+ * @param int $depth Depth of menu item. Used for padding.
50
+ * @param array $args Not used.
51
+ * @param int $id Not used.
52
+ */
53
+ public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
54
+ global $_wp_nav_menu_max_depth;
55
+
56
+ $_wp_nav_menu_max_depth = $depth > $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth;
57
+
58
+ $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
59
+
60
+ ob_start();
61
+ $item_id = esc_attr( $item->ID );
62
+ $removed_args = array(
63
+ 'action',
64
+ 'customlink-tab',
65
+ 'edit-menu-item',
66
+ 'menu-item',
67
+ 'page-tab',
68
+ '_wpnonce',
69
+ );
70
+
71
+ $original_title = '';
72
+ if ( 'taxonomy' == $item->type ) {
73
+ $original_title = get_term_field( 'name', $item->object_id, $item->object, 'raw' );
74
+ if ( is_wp_error( $original_title ) )
75
+ $original_title = false;
76
+ } elseif ( 'post_type' == $item->type ) {
77
+ $original_object = get_post( $item->object_id );
78
+ $original_title = $original_object->post_title;
79
+ }
80
+
81
+ $classes = array(
82
+ 'menu-item menu-item-depth-' . $depth,
83
+ 'menu-item-' . esc_attr( $item->object ),
84
+ 'menu-item-edit-' . ( ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? 'active' : 'inactive'),
85
+ );
86
+
87
+ $title = $item->title;
88
+
89
+ if ( ! empty( $item->_invalid ) ) {
90
+ $classes[] = 'menu-item-invalid';
91
+ /* translators: %s: title of menu item which is invalid */
92
+ $title = sprintf( esc_html__( '%s (Invalid)', 'wp-members' ), $item->title );
93
+ } elseif ( isset( $item->post_status ) && 'draft' == $item->post_status ) {
94
+ $classes[] = 'pending';
95
+ /* translators: %s: title of menu item in draft status */
96
+ $title = sprintf( esc_html__( '%s (Pending)', 'wp-members'), $item->title );
97
+ }
98
+
99
+ $title = empty( $item->label ) ? $title : $item->label;
100
+
101
+ ?>
102
+ <li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>">
103
+ <div class="menu-item-bar">
104
+ <div class="menu-item-handle ui-sortable-handle">
105
+ <span class="item-title">
106
+ <span class="menu-item-title"><?php echo esc_html( $title ); ?></span>
107
+ <span class="is-submenu" style="display: none;">sub item</span>
108
+ </span>
109
+ <span class="item-controls">
110
+ <span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
111
+ <span class="item-order hide-if-js">
112
+ <a href="<?php
113
+ echo wp_nonce_url(
114
+ add_query_arg(
115
+ array(
116
+ 'action' => 'move-up-menu-item',
117
+ 'menu-item' => $item_id,
118
+ ),
119
+ remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
120
+ ),
121
+ 'move-menu_item'
122
+ );
123
+ ?>" class="item-move-up" aria-label="<?php esc_attr_e( 'Move up', 'wp-members' ); ?>">&#8593;</a>
124
+ |
125
+ <a href="<?php
126
+ echo wp_nonce_url(
127
+ add_query_arg(
128
+ array(
129
+ 'action' => 'move-down-menu-item',
130
+ 'menu-item' => $item_id,
131
+ ),
132
+ remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
133
+ ),
134
+ 'move-menu_item'
135
+ );
136
+ ?>" class="item-move-down" aria-label="<?php esc_attr_e( 'Move down', 'wp-members' ); ?>">&#8595;</a>
137
+ </span>
138
+ <a class="item-edit" id="edit-<?php echo $item_id; ?>" title="<?php esc_attr_e( 'Edit Menu Item', 'wp-members' ); ?>" href="<?php
139
+ echo ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? admin_url( 'nav-menus.php' ) : add_query_arg( 'edit-menu-item', $item_id, remove_query_arg( $removed_args, admin_url( 'nav-menus.php#menu-item-settings-' . $item_id ) ) );
140
+ ?>"><span class="screen-reader-text"><?php esc_html_e( 'Edit', 'wp-members' ); ?></span></a>
141
+ </span>
142
+ </div>
143
+ </div>
144
+
145
+ <div class="menu-item-settings wp-clearfix" id="menu-item-settings-<?php echo $item_id; ?>">
146
+ <?php if( 'custom' == $item->type ) : ?>
147
+ <p class="field-url description description-wide">
148
+ <label for="edit-menu-item-url-<?php echo $item_id; ?>">
149
+ <?php _e( 'URL' ); ?><br />
150
+ <input type="text" id="edit-menu-item-url-<?php echo $item_id; ?>" class="widefat code edit-menu-item-url" name="menu-item-url[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->url ); ?>" />
151
+ </label>
152
+ </p>
153
+ <?php endif; ?>
154
+ <p class="description description-thin">
155
+ <label for="edit-menu-item-title-<?php echo $item_id; ?>">
156
+ <?php _e( 'Navigation Label' ); ?><br />
157
+ <input type="text" id="edit-menu-item-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-title" name="menu-item-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->title ); ?>" />
158
+ </label>
159
+ </p>
160
+ <p class="description description-thin">
161
+ <label for="edit-menu-item-attr-title-<?php echo $item_id; ?>">
162
+ <?php _e( 'Title Attribute' ); ?><br />
163
+ <input type="text" id="edit-menu-item-attr-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-attr-title" name="menu-item-attr-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->post_excerpt ); ?>" />
164
+ </label>
165
+ </p>
166
+ <p class="field-link-target description">
167
+ <label for="edit-menu-item-target-<?php echo $item_id; ?>">
168
+ <input type="checkbox" id="edit-menu-item-target-<?php echo $item_id; ?>" value="_blank" name="menu-item-target[<?php echo $item_id; ?>]"<?php checked( $item->target, '_blank' ); ?> />
169
+ <?php _e( 'Open link in a new window/tab' ); ?>
170
+ </label>
171
+ </p>
172
+ <p class="field-css-classes description description-thin">
173
+ <label for="edit-menu-item-classes-<?php echo $item_id; ?>">
174
+ <?php _e( 'CSS Classes (optional)' ); ?><br />
175
+ <input type="text" id="edit-menu-item-classes-<?php echo $item_id; ?>" class="widefat code edit-menu-item-classes" name="menu-item-classes[<?php echo $item_id; ?>]" value="<?php echo esc_attr( implode(' ', $item->classes ) ); ?>" />
176
+ </label>
177
+ </p>
178
+ <p class="field-xfn description description-thin">
179
+ <label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
180
+ <?php _e( 'Link Relationship (XFN)' ); ?><br />
181
+ <input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>" class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->xfn ); ?>" />
182
+ </label>
183
+ </p>
184
+ <p class="field-description description description-wide">
185
+ <label for="edit-menu-item-description-<?php echo $item_id; ?>">
186
+ <?php _e( 'Description' ); ?><br />
187
+ <textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
188
+ <span class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>
189
+ </label>
190
+ </p>
191
+ <?php
192
+ // This is the added section
193
+ /**
194
+ * Fires just before the move buttons of a nav menu item in the menu editor.
195
+ *
196
+ * @since 3.3.0
197
+ *
198
+ * @param int $item_id Menu item ID.
199
+ * @param WP_Post $item Menu item data object.
200
+ * @param int $depth Depth of menu item. Used for padding.
201
+ * @param stdClass $args An object of menu item arguments.
202
+ * @param int $id Nav menu ID.
203
+ */
204
+ do_action( 'wp_nav_menu_item_custom_fields', $item_id, $item, $depth, $args, $id );
205
+ // end added section
206
+ ?>
207
+ <div class="menu-item-actions description-wide submitbox">
208
+ <?php if( 'custom' != $item->type && $original_title !== false ) : ?>
209
+ <p class="link-to-original">
210
+ <?php printf( esc_html__( 'Original: %s' ), '<a href="' . esc_attr( $item->url ) . '">' . esc_html( $original_title ) . '</a>' ); ?>
211
+ </p>
212
+ <?php endif; ?>
213
+ <a class="item-delete submitdelete deletion" id="delete-<?php echo esc_attr( $item_id ); ?>" href="<?php
214
+ echo wp_nonce_url(
215
+ add_query_arg(
216
+ array(
217
+ 'action' => 'delete-menu-item',
218
+ 'menu-item' => $item_id,
219
+ ),
220
+ remove_query_arg( $removed_args, admin_url( 'nav-menus.php' ) )
221
+ ),
222
+ 'delete-menu_item_' . esc_attr( $item_id )
223
+ ); ?>"><?php _e('Remove'); ?></a> <span class="meta-sep"> | </span> <a class="item-cancel submitcancel" id="cancel-<?php echo $item_id; ?>" href="<?php echo esc_url( add_query_arg( array('edit-menu-item' => $item_id, 'cancel' => time()), remove_query_arg( $removed_args, admin_url( 'nav-menus.php' ) ) ) );
224
+ ?>#menu-item-settings-<?php echo $item_id; ?>"><?php _e('Cancel'); ?></a>
225
+ </div>
226
+
227
+ <input class="menu-item-data-db-id" type="hidden" name="menu-item-db-id[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo $item_id; ?>" />
228
+ <input class="menu-item-data-object-id" type="hidden" name="menu-item-object-id[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->object_id ); ?>" />
229
+ <input class="menu-item-data-object" type="hidden" name="menu-item-object[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->object ); ?>" />
230
+ <input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->menu_item_parent ); ?>" />
231
+ <input class="menu-item-data-position" type="hidden" name="menu-item-position[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->menu_order ); ?>" />
232
+ <input class="menu-item-data-type" type="hidden" name="menu-item-type[<?php echo esc_attr( $item_id ); ?>]" value="<?php echo esc_attr( $item->type ); ?>" />
233
+ </div><!-- .menu-item-settings-->
234
+ <ul class="menu-item-transport"></ul>
235
+ <?php
236
+
237
+ $output .= ob_get_clean();
238
+
239
+ }
240
+
241
+ } // Walker_Nav_Menu_Edit
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: cbutlerjr
3
  Tags: access, authentication, content, login, member, membership, password, protect, register, registration, restriction, subscriber
4
  Requires at least: 4.0
5
  Tested up to: 5.4
6
- Stable tag: 3.3.3
7
  License: GPLv2
8
 
9
  == Description ==
@@ -100,7 +100,7 @@ The FAQs are maintained at https://rocketgeek.com/plugins/wp-members/docs/faqs/
100
 
101
  == Upgrade Notice ==
102
 
103
- WP-Members 3.3.0 is a major update. WP-Members 3.3.3 is an improvement release. See changelog for important details. Minimum WP version is 4.0.
104
 
105
 
106
  == Screenshots ==
@@ -124,6 +124,37 @@ WP-Members 3.3.0 is a major update. WP-Members 3.3.3 is an improvement release.
124
 
125
  == Changelog ==
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  = 3.3.3 =
128
 
129
  * If WooCommerce is active, any standard WC user meta fields are removed from the WP-Members additional fields in the User Profile Edit (since they already display in the WC field blocks).
3
  Tags: access, authentication, content, login, member, membership, password, protect, register, registration, restriction, subscriber
4
  Requires at least: 4.0
5
  Tested up to: 5.4
6
+ Stable tag: 3.3.4.3
7
  License: GPLv2
8
 
9
  == Description ==
100
 
101
  == Upgrade Notice ==
102
 
103
+ WP-Members 3.3.0 is a major update. WP-Members 3.3.4 is an improvement release. See changelog for important details. Minimum WP version is 4.0.
104
 
105
 
106
  == Screenshots ==
124
 
125
  == Changelog ==
126
 
127
+ = 3.3.4.3 =
128
+
129
+ * Fixes bug where URL field is not filled when registering via WooCommerce checkout (field was handled as user meta).
130
+ * Fixes bug where TOS field did not include link to terms page when registering via WooCommerce checkout.
131
+ * Fixes bug where required field indicator did not properly display for custom fields type in WooCommerce checkout (multiple select, multiple checkbox, radio).
132
+ * Fixed an issue that caused the "membership" field selector/type to display as a text input in Users > Add New instead of a dropdown/select.
133
+
134
+ = 3.3.4.2 =
135
+
136
+ * Only run the woocommerce_form_field_{field_type} filter on fields in the WP-Members fields array (ignore all others).
137
+ * Only run woocommerce_checkout_fields filter if user is not logged in (adds WP-Members fields to WC checkout, if user is logged in, data should be edited in profile).
138
+ * Bug fix from 3.3.4 that caused register form heading to be empty when the register form shortcode is used.
139
+
140
+ = 3.3.4.1 =
141
+
142
+ * The 3.3.4 release contained some additional code used to debug the WooCommerce checkout. This causes an issue with the checkout process for general use. This update patches that by removing this code. You only need to update if you use WP-Members with WooCommerce.
143
+
144
+ = 3.3.4 =
145
+
146
+ * Updated pre_get_posts to merge post__not_in with any existing values. This will allow for better integration with other plugins (such as Search Exclude).
147
+ * Updated pre_get_posts to fire later (20) in case another plugin is adding values to be excluded. This will prevent any hidden posts from being dropped by the other plugin's process.
148
+ * Added wpmem_hidden_posts and wpmem_posts__not_in filters.
149
+ * Fixed logic in upload input type (image or file) to correct undefined variable ($file_type).
150
+ * Added function_exists check for wpmem_renew() (a PayPal extension function used in the core plugin).
151
+ * Fixed function name typo for wpmem_a_extend_user() (a PayPal extension function used in the core plugin).
152
+ * Updated product access shortcode error message to use the product_restricted message and changed the class to product_restricted_msg
153
+ * Updated CAPTCHA class for more flexibility (can now be implemented into API for calling directly in the login or other forms).
154
+ * Moved user export function from Admin API to User API.
155
+ * Fixed adding WP-Members fields to WooCommerce checkout.
156
+
157
+
158
  = 3.3.3 =
159
 
160
  * If WooCommerce is active, any standard WC user meta fields are removed from the WP-Members additional fields in the User Profile Edit (since they already display in the WC field blocks).
wp-members.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: WP-Members
4
  Plugin URI: https://rocketgeek.com
5
  Description: WP access restriction and user registration. For more information on plugin features, refer to <a href="https://rocketgeek.com/plugins/wp-members/users-guide/">the online Users Guide</a>. A <a href="https://rocketgeek.com/plugins/wp-members/quick-start-guide/">Quick Start Guide</a> is also available. WP-Members(tm) is a trademark of butlerblog.com.
6
- Version: 3.3.3
7
  Author: Chad Butler
8
  Author URI: http://butlerblog.com/
9
  Text Domain: wp-members
@@ -64,7 +64,7 @@ if ( ! defined( 'ABSPATH' ) ) {
64
  }
65
 
66
  // Initialize constants.
67
- define( 'WPMEM_VERSION', '3.3.3' );
68
  define( 'WPMEM_DB_VERSION', '2.2.0' );
69
  define( 'WPMEM_PATH', plugin_dir_path( __FILE__ ) );
70
 
3
  Plugin Name: WP-Members
4
  Plugin URI: https://rocketgeek.com
5
  Description: WP access restriction and user registration. For more information on plugin features, refer to <a href="https://rocketgeek.com/plugins/wp-members/users-guide/">the online Users Guide</a>. A <a href="https://rocketgeek.com/plugins/wp-members/quick-start-guide/">Quick Start Guide</a> is also available. WP-Members(tm) is a trademark of butlerblog.com.
6
+ Version: 3.3.4.3
7
  Author: Chad Butler
8
  Author URI: http://butlerblog.com/
9
  Text Domain: wp-members
64
  }
65
 
66
  // Initialize constants.
67
+ define( 'WPMEM_VERSION', '3.3.4.3' );
68
  define( 'WPMEM_DB_VERSION', '2.2.0' );
69
  define( 'WPMEM_PATH', plugin_dir_path( __FILE__ ) );
70