Headline
CVE-2020-36754: Changeset 2368689 for paid-memberships-pro – WordPress Plugin Repository
The Paid Memberships Pro plugin for WordPress is vulnerable to Cross-Site Request Forgery in versions up to, and including, 2.4.2. This is due to missing or incorrect nonce validation on the pmpro_page_save() function. This makes it possible for unauthenticated attackers to save pages via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
Legend:
Unmodified
Added
Removed
paid-memberships-pro/tags/2.4.3/CHANGELOG.txt
r2368140
r2368689
1
1
\== Changelog ==
2
\= 2.4.3 - 2020-08-25
3
\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)
4
\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.
5
\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.
6
2
7
\= 2.4.2 - 2020-08-24
3
8
\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.
paid-memberships-pro/tags/2.4.3/includes/metaboxes.php
r2098264
r2368689
1
1
<?php
2
/\*
3
Require Membership Meta Box
4
\*/
5
function pmpro\_page\_meta()
6
{
2
/\*\*
3
\* Require Membership Meta Box
4
\*/
5
function pmpro\_page\_meta() {
7
6
global $post, $wpdb;
8
$membership\_levels = pmpro\_getAllLevels(true, true);
9
$page\_levels = $wpdb->get\_col("SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '{$post->ID}'");
7
$membership\_levels = pmpro\_getAllLevels( true, true );
8
$page\_levels = $wpdb->get\_col( "SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post->ID ) . "'" );
10
9
?>
11
10
<ul id="membershipschecklist" class="list:category categorychecklist form-no-clear">
12
<input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) )?>" />
11
<input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo esc\_attr( wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) ) )?>" />
13
12
<?php
14
13
$in\_member\_cat = false;
15
foreach($membership\_levels as $level)
16
{
17
?>
18
<li id="membership-level-<?php echo $level->id?>">
14
foreach( $membership\_levels as $level ) {
15
?>
16
<li id="membership-level-<?php echo esc\_attr( $level->id ); ?>">
19
17
<label class="selectit">
20
<input id="in-membership-level-<?php echo $level->id?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo $level->id?>" />
18
<input id="in-membership-level-<?php echo esc\_attr( $level->id ); ?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo esc\_attr( $level->id ) ;?>" />
21
19
<?php
22
echo $level->name;
20
echo esc\_html( $level->name );
23
21
//Check which categories are protected for this level
24
$protectedcategories = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id");
22
$protectedcategories = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "'");
25
23
//See if this post is in any of the level's protected categories
26
if(in\_category($protectedcategories, $post->id))
27
{
24
if( in\_category( $protectedcategories, $post->id ) ) {
28
25
$in\_member\_cat = true;
29
26
echo ' \*';
…
…
32
29
</label>
33
30
</li>
34
<?php
31
<?php
35
32
}
36
33
?>
37
34
</ul>
38
35
<?php
39
if('post' == get\_post\_type($post) && $in\_member\_cat) { ?>
36
if( 'post' == get\_post\_type( $post ) && $in\_member\_cat ) { ?>
40
37
<p class="pmpro\_meta\_notice">\* <?php \_e("This post is already protected for this level because it is within a category that requires membership.", 'paid-memberships-pro' );?></p>
41
38
<?php
42
39
}
43
40
44
do\_action('pmpro\_after\_require\_membership\_metabox', $post);
41
do\_action( 'pmpro\_after\_require\_membership\_metabox', $post );
45
42
?>
46
43
<?php
47
44
}
48
45
49
//saves meta options
50
function pmpro\_page\_save($post\_id)
51
{
46
/\*\*
47
\* Saves meta options when a page is saved.
48
\*/
49
function pmpro\_page\_save( $post\_id ) {
52
50
global $wpdb;
53
51
54
if(empty($post\_id))
52
if( empty( $post\_id ) ) {
55
53
return false;
54
}
56
55
57
if (!empty($\_POST\['pmpro\_noncename'\]) && !wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename(\_\_FILE\_\_) )) {
56
// Post is saving somehow with our meta box not shown.
57
if ( ! isset( $\_POST\['pmpro\_noncename'\] ) ) {
58
58
return $post\_id;
59
59
}
60
60
61
// verify if this is an auto save routine. If it is our form has not been submitted, so we dont want
62
// to do anything
63
if ( defined('DOING\_AUTOSAVE') && DOING\_AUTOSAVE )
61
// Verify the nonce.
62
if ( ! wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename( \_\_FILE\_\_ ) ) ) {
64
63
return $post\_id;
65
66
// Check permissions
67
if(!empty($\_POST\['post\_type'\]) && 'page' == $\_POST\['post\_type'\] )
68
{
69
if ( !current\_user\_can( 'edit\_page', $post\_id ) )
70
return $post\_id;
71
}
72
else
73
{
74
if ( !current\_user\_can( 'edit\_post', $post\_id ) )
75
return $post\_id;
76
64
}
77
65
78
// OK, we're authenticated: we need to find and save the data
79
if(isset($\_POST\['pmpro\_noncename'\]))
80
{
81
if(!empty($\_POST\['page\_levels'\]))
82
$mydata = $\_POST\['page\_levels'\];
83
else
84
$mydata = NULL;
66
// Don't try to update meta fields on AUTOSAVE.
67
if ( defined( 'DOING\_AUTOSAVE' ) && DOING\_AUTOSAVE ) {
68
return $post\_id;
69
}
85
70
86
//remove all memberships for this page
87
$wpdb->query("DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '$post\_id'");
71
// Check permissions.
72
if( ! empty( $\_POST\['post\_type'\] ) && 'page' == $\_POST\['post\_type'\] ) {
73
if ( ! current\_user\_can( 'edit\_page', $post\_id ) ) {
74
return $post\_id;
75
}
76
} else {
77
if ( ! current\_user\_can( 'edit\_post', $post\_id ) ) {
78
return $post\_id;
79
}
80
}
88
81
89
//add new memberships for this page
90
if(is\_array($mydata))
91
{
92
foreach($mydata as $level)
93
$wpdb->query("INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval($level) . "', '" . intval($post\_id) . "')");
82
// OK, we're authenticated. We need to find and save the data.
83
if( ! empty( $\_POST\['page\_levels'\] ) ) {
84
$mydata = $\_POST\['page\_levels'\];
85
} else {
86
$mydata = NULL;
87
}
88
89
// Remove all memberships for this page.
90
$wpdb->query( "DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post\_id ) . "'" );
91
92
// Add new memberships for this page.
93
if( is\_array( $mydata ) ) {
94
foreach( $mydata as $level ) {
95
$wpdb->query( "INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval( $level ) . "', '" . intval( $post\_id ) . "')" );
94
96
}
97
}
95
98
96
return $mydata;
97
}
98
else
99
return $post\_id;
99
return $mydata;
100
100
}
101
101
102
//wrapper to add meta boxes
103
function pmpro\_page\_meta\_wrapper()
104
{
105
add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );
106
add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );
102
/\*\*
103
\* Wrapper to add meta boxes
104
\*/
105
function pmpro\_page\_meta\_wrapper() {
106
add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );
107
add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );
107
108
}
108
if (is\_admin())
109
{
110
add\_action('admin\_menu', 'pmpro\_page\_meta\_wrapper');
111
add\_action('save\_post', 'pmpro\_page\_save');
109
if ( is\_admin() ) {
110
add\_action( 'admin\_menu', 'pmpro\_page\_meta\_wrapper' );
111
add\_action( 'save\_post', 'pmpro\_page\_save' );
112
112
}
113
113
114
//show membership level restrictions on category edit
115
function pmpro\_taxonomy\_meta($term)
116
{
114
/\*\*
115
\* Show membership level restrictions on category edit.
116
\*/
117
function pmpro\_taxonomy\_meta( $term ) {
117
118
global $membership\_levels, $post, $wpdb;
118
119
119
120
$protectedlevels = array();
120
foreach($membership\_levels as $level)
121
{
122
$protectedlevel = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id AND category\_id = $term->term\_id");
123
if(!empty($protectedlevel))
124
$protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . $level->id . '">' . $level->name. '</a>';
121
foreach( $membership\_levels as $level ) {
122
$protectedlevel = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "' AND category\_id = '" . intval( $term->term\_id ) . "'" );
123
if( ! empty( $protectedlevel ) ) {
124
$protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . intval( $level->id ) . '">' . esc\_html( $level->name ) . '</a>';
125
}
125
126
}
126
if(!empty($protectedlevels))
127
{
128
?>
129
<tr class="form-field">
130
<th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>
131
<td>
132
<p><strong>
133
<?php echo implode(', ',$protectedlevels); ?></strong></p>
134
<p class="description"><?php \_e('Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>
135
</td>
136
</tr>
127
128
if( ! empty( $protectedlevels ) ) {
129
?>
130
<tr class="form-field">
131
<th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>
132
<td>
133
<p><strong>
134
<?php echo implode(', ',$protectedlevels); ?></strong></p>
135
<p class="description"><?php \_e( 'Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>
136
</td>
137
</tr>
137
138
<?php
138
139
}
paid-memberships-pro/tags/2.4.3/paid-memberships-pro.php
r2368140
r2368689
4
4
\* Plugin URI: https://www.paidmembershipspro.com
5
5
\* Description: The most complete member management and membership subscriptions plugin for WordPress.
6
\* Version: 2.4.2
6
\* Version: 2.4.3
7
7
\* Author: Stranger Studios
8
8
\* Author URI: https://www.strangerstudios.com
…
…
17
17
18
18
// version constant
19
define( 'PMPRO\_VERSION', '2.4.2' );
19
define( 'PMPRO\_VERSION', '2.4.3' );
20
20
define( 'PMPRO\_USER\_AGENT', 'Paid Memberships Pro v' . PMPRO\_VERSION . '; ' . site\_url() );
21
21
define( 'PMPRO\_MIN\_PHP\_VERSION', '5.6' );
paid-memberships-pro/tags/2.4.3/readme.txt
r2368140
r2368689
4
4
Requires at least: 4
5
5
Tested up to: 5.5
6
Stable tag: 2.4.2
6
Stable tag: 2.4.3
7
7
8
8
Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.
…
…
154
154
155
155
\== Changelog ==
156
\= 2.4.3 - 2020-08-25
157
\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)
158
\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.
159
\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.
160
156
161
\= 2.4.2 - 2020-08-24
157
162
\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.
paid-memberships-pro/trunk/CHANGELOG.txt
r2368140
r2368689
1
1
\== Changelog ==
2
\= 2.4.3 - 2020-08-25
3
\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)
4
\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.
5
\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.
6
2
7
\= 2.4.2 - 2020-08-24
3
8
\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.
paid-memberships-pro/trunk/includes/metaboxes.php
r2098264
r2368689
1
1
<?php
2
/\*
3
Require Membership Meta Box
4
\*/
5
function pmpro\_page\_meta()
6
{
2
/\*\*
3
\* Require Membership Meta Box
4
\*/
5
function pmpro\_page\_meta() {
7
6
global $post, $wpdb;
8
$membership\_levels = pmpro\_getAllLevels(true, true);
9
$page\_levels = $wpdb->get\_col("SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '{$post->ID}'");
7
$membership\_levels = pmpro\_getAllLevels( true, true );
8
$page\_levels = $wpdb->get\_col( "SELECT membership\_id FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post->ID ) . "'" );
10
9
?>
11
10
<ul id="membershipschecklist" class="list:category categorychecklist form-no-clear">
12
<input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) )?>" />
11
<input type="hidden" name="pmpro\_noncename" id="pmpro\_noncename" value="<?php echo esc\_attr( wp\_create\_nonce( plugin\_basename(\_\_FILE\_\_) ) )?>" />
13
12
<?php
14
13
$in\_member\_cat = false;
15
foreach($membership\_levels as $level)
16
{
17
?>
18
<li id="membership-level-<?php echo $level->id?>">
14
foreach( $membership\_levels as $level ) {
15
?>
16
<li id="membership-level-<?php echo esc\_attr( $level->id ); ?>">
19
17
<label class="selectit">
20
<input id="in-membership-level-<?php echo $level->id?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo $level->id?>" />
18
<input id="in-membership-level-<?php echo esc\_attr( $level->id ); ?>" type="checkbox" <?php if(in\_array($level->id, $page\_levels)) { ?>checked="checked"<?php } ?> name="page\_levels\[\]" value="<?php echo esc\_attr( $level->id ) ;?>" />
21
19
<?php
22
echo $level->name;
20
echo esc\_html( $level->name );
23
21
//Check which categories are protected for this level
24
$protectedcategories = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id");
22
$protectedcategories = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "'");
25
23
//See if this post is in any of the level's protected categories
26
if(in\_category($protectedcategories, $post->id))
27
{
24
if( in\_category( $protectedcategories, $post->id ) ) {
28
25
$in\_member\_cat = true;
29
26
echo ' \*';
…
…
32
29
</label>
33
30
</li>
34
<?php
31
<?php
35
32
}
36
33
?>
37
34
</ul>
38
35
<?php
39
if('post' == get\_post\_type($post) && $in\_member\_cat) { ?>
36
if( 'post' == get\_post\_type( $post ) && $in\_member\_cat ) { ?>
40
37
<p class="pmpro\_meta\_notice">\* <?php \_e("This post is already protected for this level because it is within a category that requires membership.", 'paid-memberships-pro' );?></p>
41
38
<?php
42
39
}
43
40
44
do\_action('pmpro\_after\_require\_membership\_metabox', $post);
41
do\_action( 'pmpro\_after\_require\_membership\_metabox', $post );
45
42
?>
46
43
<?php
47
44
}
48
45
49
//saves meta options
50
function pmpro\_page\_save($post\_id)
51
{
46
/\*\*
47
\* Saves meta options when a page is saved.
48
\*/
49
function pmpro\_page\_save( $post\_id ) {
52
50
global $wpdb;
53
51
54
if(empty($post\_id))
52
if( empty( $post\_id ) ) {
55
53
return false;
54
}
56
55
57
if (!empty($\_POST\['pmpro\_noncename'\]) && !wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename(\_\_FILE\_\_) )) {
56
// Post is saving somehow with our meta box not shown.
57
if ( ! isset( $\_POST\['pmpro\_noncename'\] ) ) {
58
58
return $post\_id;
59
59
}
60
60
61
// verify if this is an auto save routine. If it is our form has not been submitted, so we dont want
62
// to do anything
63
if ( defined('DOING\_AUTOSAVE') && DOING\_AUTOSAVE )
61
// Verify the nonce.
62
if ( ! wp\_verify\_nonce( $\_POST\['pmpro\_noncename'\], plugin\_basename( \_\_FILE\_\_ ) ) ) {
64
63
return $post\_id;
65
66
// Check permissions
67
if(!empty($\_POST\['post\_type'\]) && 'page' == $\_POST\['post\_type'\] )
68
{
69
if ( !current\_user\_can( 'edit\_page', $post\_id ) )
70
return $post\_id;
71
}
72
else
73
{
74
if ( !current\_user\_can( 'edit\_post', $post\_id ) )
75
return $post\_id;
76
64
}
77
65
78
// OK, we're authenticated: we need to find and save the data
79
if(isset($\_POST\['pmpro\_noncename'\]))
80
{
81
if(!empty($\_POST\['page\_levels'\]))
82
$mydata = $\_POST\['page\_levels'\];
83
else
84
$mydata = NULL;
66
// Don't try to update meta fields on AUTOSAVE.
67
if ( defined( 'DOING\_AUTOSAVE' ) && DOING\_AUTOSAVE ) {
68
return $post\_id;
69
}
85
70
86
//remove all memberships for this page
87
$wpdb->query("DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '$post\_id'");
71
// Check permissions.
72
if( ! empty( $\_POST\['post\_type'\] ) && 'page' == $\_POST\['post\_type'\] ) {
73
if ( ! current\_user\_can( 'edit\_page', $post\_id ) ) {
74
return $post\_id;
75
}
76
} else {
77
if ( ! current\_user\_can( 'edit\_post', $post\_id ) ) {
78
return $post\_id;
79
}
80
}
88
81
89
//add new memberships for this page
90
if(is\_array($mydata))
91
{
92
foreach($mydata as $level)
93
$wpdb->query("INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval($level) . "', '" . intval($post\_id) . "')");
82
// OK, we're authenticated. We need to find and save the data.
83
if( ! empty( $\_POST\['page\_levels'\] ) ) {
84
$mydata = $\_POST\['page\_levels'\];
85
} else {
86
$mydata = NULL;
87
}
88
89
// Remove all memberships for this page.
90
$wpdb->query( "DELETE FROM {$wpdb->pmpro\_memberships\_pages} WHERE page\_id = '" . intval( $post\_id ) . "'" );
91
92
// Add new memberships for this page.
93
if( is\_array( $mydata ) ) {
94
foreach( $mydata as $level ) {
95
$wpdb->query( "INSERT INTO {$wpdb->pmpro\_memberships\_pages} (membership\_id, page\_id) VALUES('" . intval( $level ) . "', '" . intval( $post\_id ) . "')" );
94
96
}
97
}
95
98
96
return $mydata;
97
}
98
else
99
return $post\_id;
99
return $mydata;
100
100
}
101
101
102
//wrapper to add meta boxes
103
function pmpro\_page\_meta\_wrapper()
104
{
105
add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );
106
add\_meta\_box('pmpro\_page\_meta', \_\_('Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );
102
/\*\*
103
\* Wrapper to add meta boxes
104
\*/
105
function pmpro\_page\_meta\_wrapper() {
106
add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'page', 'side', 'high' );
107
add\_meta\_box( 'pmpro\_page\_meta', \_\_( 'Require Membership', 'paid-memberships-pro' ), 'pmpro\_page\_meta', 'post', 'side', 'high' );
107
108
}
108
if (is\_admin())
109
{
110
add\_action('admin\_menu', 'pmpro\_page\_meta\_wrapper');
111
add\_action('save\_post', 'pmpro\_page\_save');
109
if ( is\_admin() ) {
110
add\_action( 'admin\_menu', 'pmpro\_page\_meta\_wrapper' );
111
add\_action( 'save\_post', 'pmpro\_page\_save' );
112
112
}
113
113
114
//show membership level restrictions on category edit
115
function pmpro\_taxonomy\_meta($term)
116
{
114
/\*\*
115
\* Show membership level restrictions on category edit.
116
\*/
117
function pmpro\_taxonomy\_meta( $term ) {
117
118
global $membership\_levels, $post, $wpdb;
118
119
119
120
$protectedlevels = array();
120
foreach($membership\_levels as $level)
121
{
122
$protectedlevel = $wpdb->get\_col("SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = $level->id AND category\_id = $term->term\_id");
123
if(!empty($protectedlevel))
124
$protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . $level->id . '">' . $level->name. '</a>';
121
foreach( $membership\_levels as $level ) {
122
$protectedlevel = $wpdb->get\_col( "SELECT category\_id FROM $wpdb->pmpro\_memberships\_categories WHERE membership\_id = '" . intval( $level->id ) . "' AND category\_id = '" . intval( $term->term\_id ) . "'" );
123
if( ! empty( $protectedlevel ) ) {
124
$protectedlevels\[\] .= '<a target="\_blank" href="admin.php?page=pmpro-membershiplevels&edit=' . intval( $level->id ) . '">' . esc\_html( $level->name ) . '</a>';
125
}
125
126
}
126
if(!empty($protectedlevels))
127
{
128
?>
129
<tr class="form-field">
130
<th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>
131
<td>
132
<p><strong>
133
<?php echo implode(', ',$protectedlevels); ?></strong></p>
134
<p class="description"><?php \_e('Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>
135
</td>
136
</tr>
127
128
if( ! empty( $protectedlevels ) ) {
129
?>
130
<tr class="form-field">
131
<th scope="row" valign="top"><?php \_e( 'Membership Levels', 'paid-memberships-pro' ); ?></label></th>
132
<td>
133
<p><strong>
134
<?php echo implode(', ',$protectedlevels); ?></strong></p>
135
<p class="description"><?php \_e( 'Only members of these levels will be able to view posts in this category.', 'paid-memberships-pro' ); ?></p>
136
</td>
137
</tr>
137
138
<?php
138
139
}
paid-memberships-pro/trunk/paid-memberships-pro.php
r2368140
r2368689
4
4
\* Plugin URI: https://www.paidmembershipspro.com
5
5
\* Description: The most complete member management and membership subscriptions plugin for WordPress.
6
\* Version: 2.4.2
6
\* Version: 2.4.3
7
7
\* Author: Stranger Studios
8
8
\* Author URI: https://www.strangerstudios.com
…
…
17
17
18
18
// version constant
19
define( 'PMPRO\_VERSION', '2.4.2' );
19
define( 'PMPRO\_VERSION', '2.4.3' );
20
20
define( 'PMPRO\_USER\_AGENT', 'Paid Memberships Pro v' . PMPRO\_VERSION . '; ' . site\_url() );
21
21
define( 'PMPRO\_MIN\_PHP\_VERSION', '5.6' );
paid-memberships-pro/trunk/readme.txt
r2368140
r2368689
4
4
Requires at least: 4
5
5
Tested up to: 5.5
6
Stable tag: 2.4.2
6
Stable tag: 2.4.3
7
7
8
8
Get Paid with Paid Memberships Pro: The most complete member management and membership subscriptions plugin for your WordPress site.
…
…
154
154
155
155
\== Changelog ==
156
\= 2.4.3 - 2020-08-25
157
\* SECURITY: Fixed a cross-site scripting vulnerability in the code that updates the Required Membership settings on a post. This vulnerability could have been used in conjunction with other security vulnerabilities to trick an admin into editing the membership settings for a page, potentially exposing members only content to non-members. It is unlikely that there was any active exploitation of this vulnerability. This issue may also have shown up as a bug on some sites using page builders, where the membership settings for a post would be cleared out when editing a post. (Thanks to the wp.org plugin review team for catching this issue.)
158
\* SECURITY: Better escaping of variables shown in the Require Membership meta box and related SQL queries.
159
\* BUG FIX/ENHANCEMENT: Renamed the Vietnamese language files to match what is expected.
160
156
161
\= 2.4.2 - 2020-08-24
157
162
\* SECURITY: Updated the PMPro REST API endpoints accessed via the GET method to also require appropriate capabilities to access. The membership confirmation text will be hidden from non-members and non-admins. The endpoints to check a user's level or access to a post require the pmpro\_edit\_memberships capability now. You should make sure your API users have the appropriate capabilities to use the API. You can use the pmpro\_rest\_api\_route\_capabilities filter and/or pmpro\_rest\_api\_permissions filter to change this behavior.
Note: See TracChangeset for help on using the changeset viewer.