MainWP Child - Version 4.1.1

Version Description

  • 10-7-20 =
  • Fixed: An issue with creating new users
  • Fixed: An issue with cloning sites
  • Fixed: An issue with creating post tags
  • Updated: Multiple database query improvements
  • Preventative: Multiple security improvements
Download this release

Release Info

Developer mainwp
Plugin Icon 128x128 MainWP Child
Version 4.1.1
Comparing to
See all releases

Code changes from version 4.1 to 4.1.1

class/class-mainwp-child-comments.php CHANGED
@@ -154,16 +154,16 @@ class MainWP_Child_Comments {
154
  add_filter( 'comments_clauses', array( &$this, 'comments_clauses' ) );
155
 
156
  if ( isset( $_POST['postId'] ) ) {
157
- $this->comments_and_clauses .= " AND $wpdb->comments.comment_post_ID = " . sanitize_text_field( wp_unslash( $_POST['postId'] ) );
158
  } else {
159
- if ( isset( $_POST['keyword'] ) ) {
160
- $this->comments_and_clauses .= " AND $wpdb->comments.comment_content LIKE '%" . sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) . "%'";
161
  }
162
  if ( isset( $_POST['dtsstart'] ) && '' !== $_POST['dtsstart'] ) {
163
- $this->comments_and_clauses .= " AND $wpdb->comments.comment_date > '" . sanitize_text_field( wp_unslash( $_POST['dtsstart'] ) ) . "'";
164
  }
165
  if ( isset( $_POST['dtsstop'] ) && '' !== $_POST['dtsstop'] ) {
166
- $this->comments_and_clauses .= " AND $wpdb->comments.comment_date < '" . sanitize_text_field( wp_unslash( $_POST['dtsstop'] ) ) . "'";
167
  }
168
  }
169
 
154
  add_filter( 'comments_clauses', array( &$this, 'comments_clauses' ) );
155
 
156
  if ( isset( $_POST['postId'] ) ) {
157
+ $this->comments_and_clauses .= $wpdb->prepare( " AND $wpdb->comments.comment_post_ID = %d ", sanitize_text_field( wp_unslash( $_POST['postId'] ) ) );
158
  } else {
159
+ if ( isset( $_POST['keyword'] ) && '' !== $_POST['keyword'] ) {
160
+ $this->comments_and_clauses .= $wpdb->prepare( " AND $wpdb->comments.comment_content LIKE %s ", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) ) . '%' );
161
  }
162
  if ( isset( $_POST['dtsstart'] ) && '' !== $_POST['dtsstart'] ) {
163
+ $this->comments_and_clauses .= $wpdb->prepare( " AND $wpdb->comments.comment_date > %s ", $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['dtsstart'] ) ) ) );
164
  }
165
  if ( isset( $_POST['dtsstop'] ) && '' !== $_POST['dtsstop'] ) {
166
+ $this->comments_and_clauses .= $wpdb->prepare( " AND $wpdb->comments.comment_date < %s ", $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['dtsstop'] ) ) ) );
167
  }
168
  }
169
 
class/class-mainwp-child-posts.php CHANGED
@@ -308,32 +308,32 @@ class MainWP_Child_Posts {
308
  add_filter( 'posts_where', array( &$this, 'posts_where' ) );
309
  $where_post_date = isset( $_POST['where_post_date'] ) && ! empty( $_POST['where_post_date'] ) ? true : false;
310
  if ( isset( $_POST['postId'] ) ) {
311
- $this->posts_where_suffix .= " AND $wpdb->posts.ID = " . sanitize_text_field( wp_unslash( $_POST['postId'] ) );
312
  } elseif ( isset( $_POST['userId'] ) ) {
313
- $this->posts_where_suffix .= " AND $wpdb->posts.post_author = " . sanitize_text_field( wp_unslash( $_POST['userId'] ) );
314
  } else {
315
- if ( isset( $_POST['keyword'] ) ) {
316
  $search_on = isset( $_POST['search_on'] ) ? sanitize_text_field( wp_unslash( $_POST['search_on'] ) ) : '';
317
  if ( 'title' == $search_on ) {
318
- $this->posts_where_suffix .= " AND ( $wpdb->posts.post_title LIKE '%" . sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) . "%' )";
319
  } elseif ( 'content' == $search_on ) {
320
- $this->posts_where_suffix .= " AND ( $wpdb->posts.post_content LIKE '%" . sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) . "%' )";
321
  } else {
322
- $this->posts_where_suffix .= " AND ( $wpdb->posts.post_content LIKE '%" . sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) . "%' OR $wpdb->posts.post_title LIKE '%" . sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) . "%' )";
323
  }
324
  }
325
  if ( isset( $_POST['dtsstart'] ) && '' !== $_POST['dtsstart'] ) {
326
  if ( $where_post_date ) {
327
- $this->posts_where_suffix .= " AND $wpdb->posts.post_date > '" . sanitize_text_field( wp_unslash( $_POST['dtsstart'] ) ) . "'";
328
  } else {
329
- $this->posts_where_suffix .= " AND $wpdb->posts.post_modified > '" . sanitize_text_field( wp_unslash( $_POST['dtsstart'] ) ) . "'";
330
  }
331
  }
332
  if ( isset( $_POST['dtsstop'] ) && '' !== $_POST['dtsstop'] ) {
333
  if ( $where_post_date ) {
334
- $this->posts_where_suffix .= " AND $wpdb->posts.post_date < '" . sanitize_text_field( wp_unslash( $_POST['dtsstop'] ) ) . "'";
335
  } else {
336
- $this->posts_where_suffix .= " AND $wpdb->posts.post_modified < '" . sanitize_text_field( wp_unslash( $_POST['dtsstop'] ) ) . "'";
337
  }
338
  }
339
 
@@ -378,7 +378,7 @@ class MainWP_Child_Posts {
378
  $new_post = isset( $_POST['new_post'] ) ? maybe_unserialize( base64_decode( wp_unslash( $_POST['new_post'] ) ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
379
  $post_custom = isset( $_POST['post_custom'] ) ? maybe_unserialize( base64_decode( wp_unslash( $_POST['post_custom'] ) ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
380
  $post_category = isset( $_POST['post_category'] ) ? rawurldecode( base64_decode( wp_unslash( $_POST['post_category'] ) ) ) : null; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
381
- $post_tags = isset( $_POST['post_tags'] ) ? rawurldecode( wp_unslash( $new_post['post_tags'] ) ) : null;
382
  $post_featured_image = isset( $_POST['post_featured_image'] ) ? base64_decode( wp_unslash( $_POST['post_featured_image'] ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
383
  $upload_dir = isset( $_POST['mainwp_upload_dir'] ) ? maybe_unserialize( base64_decode( wp_unslash( $_POST['mainwp_upload_dir'] ) ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
384
 
@@ -810,7 +810,7 @@ class MainWP_Child_Posts {
810
  }
811
  }
812
 
813
- if ( isset( $post_tags ) && '' !== $post_tags ) {
814
  $new_post['tags_input'] = $post_tags;
815
  }
816
 
308
  add_filter( 'posts_where', array( &$this, 'posts_where' ) );
309
  $where_post_date = isset( $_POST['where_post_date'] ) && ! empty( $_POST['where_post_date'] ) ? true : false;
310
  if ( isset( $_POST['postId'] ) ) {
311
+ $this->posts_where_suffix .= $wpdb->prepare( " AND $wpdb->posts.ID = %d ", sanitize_text_field( wp_unslash( $_POST['postId'] ) ) );
312
  } elseif ( isset( $_POST['userId'] ) ) {
313
+ $this->posts_where_suffix .= $wpdb->prepare( " AND $wpdb->posts.post_author = %d ", sanitize_text_field( wp_unslash( $_POST['userId'] ) ) );
314
  } else {
315
+ if ( isset( $_POST['keyword'] ) && '' !== $_POST['keyword'] ) {
316
  $search_on = isset( $_POST['search_on'] ) ? sanitize_text_field( wp_unslash( $_POST['search_on'] ) ) : '';
317
  if ( 'title' == $search_on ) {
318
+ $this->posts_where_suffix .= $wpdb->prepare( " AND ( $wpdb->posts.post_title LIKE %s ) ", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) ) . '%' );
319
  } elseif ( 'content' == $search_on ) {
320
+ $this->posts_where_suffix .= $wpdb->prepare( " AND ( $wpdb->posts.post_content LIKE %s )", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) ) . '%' );
321
  } else {
322
+ $this->posts_where_suffix .= $wpdb->prepare( " AND ( $wpdb->posts.post_content LIKE %s OR $wpdb->posts.post_title LIKE %s )", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) ) . '%', '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) ) . '%' );
323
  }
324
  }
325
  if ( isset( $_POST['dtsstart'] ) && '' !== $_POST['dtsstart'] ) {
326
  if ( $where_post_date ) {
327
+ $this->posts_where_suffix .= $wpdb->prepare( " AND $wpdb->posts.post_date > %s", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['dtsstart'] ) ) ) . '%' );
328
  } else {
329
+ $this->posts_where_suffix .= $wpdb->prepare( " AND $wpdb->posts.post_modified > %s", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['dtsstart'] ) ) ) . '%' );
330
  }
331
  }
332
  if ( isset( $_POST['dtsstop'] ) && '' !== $_POST['dtsstop'] ) {
333
  if ( $where_post_date ) {
334
+ $this->posts_where_suffix .= $wpdb->prepare( " AND $wpdb->posts.post_date < %s ", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['dtsstop'] ) ) ) . '%' );
335
  } else {
336
+ $this->posts_where_suffix .= $wpdb->prepare( " AND $wpdb->posts.post_modified < %s", '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_POST['dtsstop'] ) ) ) . '%' );
337
  }
338
  }
339
 
378
  $new_post = isset( $_POST['new_post'] ) ? maybe_unserialize( base64_decode( wp_unslash( $_POST['new_post'] ) ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
379
  $post_custom = isset( $_POST['post_custom'] ) ? maybe_unserialize( base64_decode( wp_unslash( $_POST['post_custom'] ) ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
380
  $post_category = isset( $_POST['post_category'] ) ? rawurldecode( base64_decode( wp_unslash( $_POST['post_category'] ) ) ) : null; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
381
+ $post_tags = isset( $new_post['post_tags'] ) ? rawurldecode( $new_post['post_tags'] ) : null;
382
  $post_featured_image = isset( $_POST['post_featured_image'] ) ? base64_decode( wp_unslash( $_POST['post_featured_image'] ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
383
  $upload_dir = isset( $_POST['mainwp_upload_dir'] ) ? maybe_unserialize( base64_decode( wp_unslash( $_POST['mainwp_upload_dir'] ) ) ) : ''; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- base64_encode function is used for http encode compatible..
384
 
810
  }
811
  }
812
 
813
+ if ( isset( $post_tags ) && '' != $post_tags ) {
814
  $new_post['tags_input'] = $post_tags;
815
  }
816
 
class/class-mainwp-child-server-information.php CHANGED
@@ -88,6 +88,11 @@ class MainWP_Child_Server_Information extends MainWP_Child_Server_Information_Ba
88
  return;
89
  }
90
 
 
 
 
 
 
91
  $warnings = self::get_warnings();
92
 
93
  $dismissWarnings = get_option( 'mainwp_child_dismiss_warnings' );
@@ -185,6 +190,22 @@ class MainWP_Child_Server_Information extends MainWP_Child_Server_Information_Ba
185
  <?php
186
  }
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  /**
189
  * Render JavaScrip code for the Server Information page.
190
  *
@@ -1354,12 +1375,12 @@ class MainWP_Child_Server_Information extends MainWP_Child_Server_Information_Ba
1354
 
1355
  $uniqueId = get_option( 'mainwp_child_uniqueId' );
1356
  $details = array(
1357
- 'siteurl' => array(
1358
  'title' => __( 'Site URL', 'mainwp-child' ),
1359
  'value' => get_bloginfo( 'url' ),
1360
  'desc' => get_bloginfo( 'url' ),
1361
  ),
1362
- 'adminuser' => array(
1363
  'title' => __( 'Administrator name', 'mainwp-child' ),
1364
  'value' => $current_user->user_login,
1365
  'desc' => __( 'This is your Administrator username, however, you can use any existing Administrator username.', 'mainwp-child' ),
@@ -1369,17 +1390,17 @@ class MainWP_Child_Server_Information extends MainWP_Child_Server_Information_Ba
1369
  'value' => get_bloginfo( 'name' ),
1370
  'desc' => __( 'For the friendly site name, you can use any name, this is just a suggestion.', 'mainwp-child' ),
1371
  ),
1372
- 'uniqueid' => array(
1373
  'title' => __( 'Child unique security id', 'mainwp-child' ),
1374
  'value' => ! empty( $uniqueId ) ? $uniqueId : __( 'Leave the field blank', 'mainwp-child' ),
1375
  'desc' => sprintf( __( 'Child unique security id is not required, however, since you have enabled it, you need to add it to your %s dashboard.', 'mainwp-child' ), stripslashes( $branding_title ) ),
1376
  ),
1377
- 'verify_ssl' => array(
1378
  'title' => __( 'Verify certificate', 'mainwp-child' ),
1379
  'value' => __( 'Yes', 'mainwp-child' ),
1380
  'desc' => __( 'If there is an issue with SSL certificate on this site, try to set this option to No.', 'mainwp-child' ),
1381
  ),
1382
- 'ssl_version' => array(
1383
  'title' => __( 'SSL version', 'mainwp-child' ),
1384
  'value' => __( 'Auto Detect', 'mainwp-child' ),
1385
  'desc' => __( 'Auto Detect', 'mainwp-child' ),
88
  return;
89
  }
90
 
91
+ // improved query.
92
+ if ( self::is_mainwp_pages() ) {
93
+ return;
94
+ }
95
+
96
  $warnings = self::get_warnings();
97
 
98
  $dismissWarnings = get_option( 'mainwp_child_dismiss_warnings' );
190
  <?php
191
  }
192
 
193
+ /**
194
+ * Method is_mainwp_pages()
195
+ *
196
+ * Get the current page and check it for "mainwp_".
197
+ *
198
+ * @return boolean ture|false.
199
+ */
200
+ public static function is_mainwp_pages() {
201
+ $screen = get_current_screen();
202
+ if ( $screen && strpos( $screen->base, 'mainwp_' ) !== false && strpos( $screen->base, 'mainwp_child_tab' ) === false ) {
203
+ return true;
204
+ }
205
+
206
+ return false;
207
+ }
208
+
209
  /**
210
  * Render JavaScrip code for the Server Information page.
211
  *
1375
 
1376
  $uniqueId = get_option( 'mainwp_child_uniqueId' );
1377
  $details = array(
1378
+ 'siteurl' => array(
1379
  'title' => __( 'Site URL', 'mainwp-child' ),
1380
  'value' => get_bloginfo( 'url' ),
1381
  'desc' => get_bloginfo( 'url' ),
1382
  ),
1383
+ 'adminuser' => array(
1384
  'title' => __( 'Administrator name', 'mainwp-child' ),
1385
  'value' => $current_user->user_login,
1386
  'desc' => __( 'This is your Administrator username, however, you can use any existing Administrator username.', 'mainwp-child' ),
1390
  'value' => get_bloginfo( 'name' ),
1391
  'desc' => __( 'For the friendly site name, you can use any name, this is just a suggestion.', 'mainwp-child' ),
1392
  ),
1393
+ 'uniqueid' => array(
1394
  'title' => __( 'Child unique security id', 'mainwp-child' ),
1395
  'value' => ! empty( $uniqueId ) ? $uniqueId : __( 'Leave the field blank', 'mainwp-child' ),
1396
  'desc' => sprintf( __( 'Child unique security id is not required, however, since you have enabled it, you need to add it to your %s dashboard.', 'mainwp-child' ), stripslashes( $branding_title ) ),
1397
  ),
1398
+ 'verify_ssl' => array(
1399
  'title' => __( 'Verify certificate', 'mainwp-child' ),
1400
  'value' => __( 'Yes', 'mainwp-child' ),
1401
  'desc' => __( 'If there is an issue with SSL certificate on this site, try to set this option to No.', 'mainwp-child' ),
1402
  ),
1403
+ 'ssl_version' => array(
1404
  'title' => __( 'SSL version', 'mainwp-child' ),
1405
  'value' => __( 'Auto Detect', 'mainwp-child' ),
1406
  'desc' => __( 'Auto Detect', 'mainwp-child' ),
class/class-mainwp-child-stats.php CHANGED
@@ -214,7 +214,7 @@ class MainWP_Child_Stats {
214
  $information['recent_posts'] = MainWP_Child_Posts::get_instance()->get_recent_posts( array( 'publish', 'draft', 'pending', 'trash', 'future' ), $recent_number );
215
  $information['recent_pages'] = MainWP_Child_Posts::get_instance()->get_recent_posts( array( 'publish', 'draft', 'pending', 'trash', 'future' ), $recent_number, 'page' );
216
  $information['securityIssues'] = MainWP_Security::get_stats_security();
217
- $information['securityStats'] = MainWP_Child_Misc::get_security_stats( true );
218
 
219
  // Directory listings!
220
  $information['directories'] = $this->scan_dir( ABSPATH, 3 );
214
  $information['recent_posts'] = MainWP_Child_Posts::get_instance()->get_recent_posts( array( 'publish', 'draft', 'pending', 'trash', 'future' ), $recent_number );
215
  $information['recent_pages'] = MainWP_Child_Posts::get_instance()->get_recent_posts( array( 'publish', 'draft', 'pending', 'trash', 'future' ), $recent_number, 'page' );
216
  $information['securityIssues'] = MainWP_Security::get_stats_security();
217
+ $information['securityStats'] = MainWP_Child_Misc::get_instance()->get_security_stats( true );
218
 
219
  // Directory listings!
220
  $information['directories'] = $this->scan_dir( ABSPATH, 3 );
class/class-mainwp-child-users.php CHANGED
@@ -62,7 +62,7 @@ class MainWP_Child_Users {
62
  */
63
  public function user_action() {
64
  $action = ! empty( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : '';
65
- $extra = isset( $_POST['extra'] ) ? sanitize_text_field( wp_unslash( $_POST['extra'] ) ) : '';
66
  $userId = isset( $_POST['id'] ) ? sanitize_text_field( wp_unslash( $_POST['id'] ) ) : '';
67
  $user_pass = isset( $_POST['user_pass'] ) ? wp_unslash( $_POST['user_pass'] ) : '';
68
  $failed = false;
@@ -97,7 +97,7 @@ class MainWP_Child_Users {
97
  $failed = true;
98
  }
99
  } elseif ( 'update_user' === $action ) {
100
- $my_user = isset( $_POST['extra'] ) ? sanitize_text_field( wp_unslash( $_POST['extra'] ) ) : '';
101
  if ( is_array( $my_user ) ) {
102
  foreach ( $my_user as $idx => $val ) {
103
  if ( 'donotupdate' === $val || ( empty( $val ) && 'role' !== $idx ) ) {
62
  */
63
  public function user_action() {
64
  $action = ! empty( $_POST['action'] ) ? sanitize_text_field( wp_unslash( $_POST['action'] ) ) : '';
65
+ $extra = isset( $_POST['extra'] ) ? wp_unslash( $_POST['extra'] ) : '';
66
  $userId = isset( $_POST['id'] ) ? sanitize_text_field( wp_unslash( $_POST['id'] ) ) : '';
67
  $user_pass = isset( $_POST['user_pass'] ) ? wp_unslash( $_POST['user_pass'] ) : '';
68
  $failed = false;
97
  $failed = true;
98
  }
99
  } elseif ( 'update_user' === $action ) {
100
+ $my_user = $extra;
101
  if ( is_array( $my_user ) ) {
102
  foreach ( $my_user as $idx => $val ) {
103
  if ( 'donotupdate' === $val || ( empty( $val ) && 'role' !== $idx ) ) {
class/class-mainwp-child.php CHANGED
@@ -33,7 +33,7 @@ class MainWP_Child {
33
  *
34
  * @var string MainWP Child plugin version.
35
  */
36
- public static $version = '4.1';
37
 
38
  /**
39
  * Private variable containing the latest MainWP Child update version.
@@ -135,7 +135,7 @@ class MainWP_Child {
135
  $notoptions = false;
136
  }
137
 
138
- if ( ! isset( $alloptions['mainwp_db_version'] ) ) {
139
  $suppress = $wpdb->suppress_errors();
140
  $options = array(
141
  'mainwp_child_auth',
@@ -156,6 +156,7 @@ class MainWP_Child {
156
  'mainwp_linkschecker_ext_enabled',
157
  'mainwp_child_branding_settings',
158
  'mainwp_child_plugintheme_days_outdate',
 
159
  );
160
  $query = "SELECT option_name, option_value FROM $wpdb->options WHERE option_name in (";
161
  foreach ( $options as $option ) {
@@ -232,7 +233,7 @@ class MainWP_Child {
232
  public function parse_init() {
233
 
234
  if ( isset( $_REQUEST['cloneFunc'] ) ) {
235
- $valid_clone = MainWP_Clone_Install::get()->request_clone_funct();
236
  if ( ! $valid_clone ) {
237
  return;
238
  }
33
  *
34
  * @var string MainWP Child plugin version.
35
  */
36
+ public static $version = '4.1.1';
37
 
38
  /**
39
  * Private variable containing the latest MainWP Child update version.
135
  $notoptions = false;
136
  }
137
 
138
+ if ( ! isset( $alloptions['mainwp_child_server'] ) ) {
139
  $suppress = $wpdb->suppress_errors();
140
  $options = array(
141
  'mainwp_child_auth',
156
  'mainwp_linkschecker_ext_enabled',
157
  'mainwp_child_branding_settings',
158
  'mainwp_child_plugintheme_days_outdate',
159
+ 'mainwp_wp_staging_ext_enabled',
160
  );
161
  $query = "SELECT option_name, option_value FROM $wpdb->options WHERE option_name in (";
162
  foreach ( $options as $option ) {
233
  public function parse_init() {
234
 
235
  if ( isset( $_REQUEST['cloneFunc'] ) ) {
236
+ $valid_clone = MainWP_Clone::instance()->request_clone_funct();
237
  if ( ! $valid_clone ) {
238
  return;
239
  }
class/class-mainwp-clone-install.php CHANGED
@@ -18,6 +18,13 @@ namespace MainWP\Child;
18
  */
19
  class MainWP_Clone_Install {
20
 
 
 
 
 
 
 
 
21
  /**
22
  * The zip backup file path.
23
  *
@@ -46,7 +53,7 @@ class MainWP_Clone_Install {
46
  *
47
  * @param string $file Archive file.
48
  */
49
- public function __construct( $file ) {
50
  require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
51
 
52
  $this->file = $file;
@@ -61,6 +68,18 @@ class MainWP_Clone_Install {
61
  }
62
  }
63
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  /**
65
  * Check for default PHP zip support.
66
  *
@@ -403,7 +422,7 @@ class MainWP_Clone_Install {
403
  $zip = new \ZipArchive();
404
  $zipRes = $zip->open( $this->file );
405
  if ( $zipRes ) {
406
- $content = $zip->get_from_name( 'clone/config.txt' );
407
  $zip->close();
408
 
409
  return $content;
@@ -747,150 +766,4 @@ class MainWP_Clone_Install {
747
  return $data;
748
  }
749
 
750
- /**
751
- * Request clone.
752
- *
753
- * @return bool|void true|void.
754
- */
755
- public function request_clone_funct() {
756
-
757
- if ( ! isset( $_REQUEST['key'] ) ) {
758
- return;
759
- }
760
- if ( ! isset( $_REQUEST['f'] ) || ( '' === $_REQUEST['f'] ) ) {
761
- return;
762
- }
763
- if ( ! isset( $_REQUEST['key'] ) || ! MainWP_Connect::instance()->is_valid_auth( wp_unslash( $_REQUEST['key'] ) ) ) {
764
- return;
765
- }
766
-
767
- $cloneFunc = isset( $_REQUEST['cloneFunc'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['cloneFunc'] ) ) : '';
768
-
769
- if ( 'dl' === $cloneFunc ) {
770
- $f = isset( $_REQUEST['f'] ) ? wp_unslash( $_REQUEST['f'] ) : '';
771
- if ( ! empty( $f ) ) {
772
- MainWP_Utility::instance()->upload_file( wp_unslash( $_REQUEST['f'] ) );
773
- }
774
- exit;
775
- } elseif ( 'deleteCloneBackup' === $cloneFunc ) {
776
- $dirs = MainWP_Helper::get_mainwp_dir( 'backup' );
777
- $backupdir = $dirs[0];
778
- $result = isset( $_POST['f'] ) ? glob( $backupdir . wp_unslash( $_POST['f'] ) ) : array();
779
- if ( 0 === count( $result ) ) {
780
- return;
781
- }
782
-
783
- unlink( $result[0] );
784
- MainWP_Helper::write( array( 'result' => 'ok' ) );
785
- } elseif ( 'createCloneBackupPoll' === $cloneFunc ) {
786
- $dirs = MainWP_Helper::get_mainwp_dir( 'backup' );
787
- $backupdir = $dirs[0];
788
- $f = isset( $_POST['f'] ) ? wp_unslash( $_POST['f'] ) : '';
789
- $archiveFile = false;
790
- if ( ! empty( $f ) ) {
791
- $result = glob( $backupdir . 'backup-' . $f . '-*' );
792
- foreach ( $result as $file ) {
793
- if ( MainWP_Clone::is_archive( $file, 'backup-' . $f . '-' ) ) {
794
- $archiveFile = $file;
795
- break;
796
- }
797
- }
798
- }
799
- if ( false === $archiveFile ) {
800
- return;
801
- }
802
-
803
- MainWP_Helper::write( array( 'size' => filesize( $archiveFile ) ) );
804
- } elseif ( 'createCloneBackup' === $cloneFunc ) {
805
- $this->create_clone_backup();
806
- }
807
- return true;
808
- }
809
-
810
- /**
811
- * Create backup of clone.
812
- */
813
- private function create_clone_backup() {
814
- MainWP_Helper::end_session();
815
- $files = glob( WP_CONTENT_DIR . '/dbBackup*.sql' );
816
- foreach ( $files as $file ) {
817
- unlink( $file );
818
- }
819
- if ( file_exists( ABSPATH . 'clone/config.txt' ) ) {
820
- unlink( ABSPATH . 'clone/config.txt' );
821
- }
822
- if ( MainWP_Helper::is_dir_empty( ABSPATH . 'clone' ) ) {
823
- rmdir( ABSPATH . 'clone' );
824
- }
825
-
826
- $wpversion = isset( $_POST['wpversion'] ) ? sanitize_text_field( wp_unslash( $_POST['wpversion'] ) ) : '';
827
- global $wp_version;
828
- $includeCoreFiles = ( $wpversion !== $wp_version );
829
- $excludes = ( isset( $_POST['exclude'] ) ? explode( ',', wp_unslash( $_POST['exclude'] ) ) : array() );
830
- $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/mainwp';
831
- $uploadDir = MainWP_Helper::get_mainwp_dir();
832
- $uploadDir = $uploadDir[0];
833
- $excludes[] = str_replace( ABSPATH, '', $uploadDir );
834
- $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/object-cache.php';
835
- if ( version_compare( phpversion(), '5.3.0' ) >= 0 || ! ini_get( 'safe_mode' ) ) {
836
- set_time_limit( 6000 );
837
- }
838
-
839
- $newExcludes = array();
840
- foreach ( $excludes as $exclude ) {
841
- $newExcludes[] = rtrim( $exclude, '/' );
842
- }
843
-
844
- $method = ( ! isset( $_POST['zipmethod'] ) ? 'tar.gz' : wp_unslash( $_POST['zipmethod'] ) );
845
- if ( 'tar.gz' === $method && ! function_exists( 'gzopen' ) ) {
846
- $method = 'zip';
847
- }
848
-
849
- $file = false;
850
- if ( isset( $_POST['f'] ) ) {
851
- $file = ! empty( $_POST['f'] ) ? wp_unslash( $_POST['f'] ) : false;
852
- } elseif ( isset( $_POST['file'] ) ) {
853
- $file = ! empty( $_POST['file'] ) ? wp_unslash( $_POST['file'] ) : false;
854
- }
855
-
856
- $res = MainWP_Backup::get()->create_full_backup( $newExcludes, $file, true, $includeCoreFiles, 0, false, false, false, false, $method );
857
- if ( ! $res ) {
858
- $information['backup'] = false;
859
- } else {
860
- $information['backup'] = $res['file'];
861
- $information['size'] = $res['filesize'];
862
- }
863
-
864
- $plugins = array();
865
- $dir = WP_CONTENT_DIR . '/plugins/';
866
- $fh = opendir( $dir );
867
- $entry = readdir( $fh );
868
- while ( $entry ) {
869
- if ( ! is_dir( $dir . $entry ) ) {
870
- continue;
871
- }
872
- if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
873
- continue;
874
- }
875
- $plugins[] = $entry;
876
- }
877
- closedir( $fh );
878
- $information['plugins'] = $plugins;
879
-
880
- $themes = array();
881
- $dir = WP_CONTENT_DIR . '/themes/';
882
- $fh = opendir( $dir );
883
- while ( $entry = readdir( $fh ) ) {
884
- if ( ! is_dir( $dir . $entry ) ) {
885
- continue;
886
- }
887
- if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
888
- continue;
889
- }
890
- $themes[] = $entry;
891
- }
892
- closedir( $fh );
893
- $information['themes'] = $themes;
894
- MainWP_Helper::write( $information );
895
- }
896
  }
18
  */
19
  class MainWP_Clone_Install {
20
 
21
+ /**
22
+ * Public static variable to hold the single instance of the class.
23
+ *
24
+ * @var mixed Default null
25
+ */
26
+ protected static $instance = null;
27
+
28
  /**
29
  * The zip backup file path.
30
  *
53
  *
54
  * @param string $file Archive file.
55
  */
56
+ public function __construct( $file = '' ) {
57
  require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
58
 
59
  $this->file = $file;
68
  }
69
  }
70
 
71
+ /**
72
+ * Create a public static instance of MainWP_Clone_Install.
73
+ *
74
+ * @return MainWP_Clone_Install
75
+ */
76
+ public static function get_instance() {
77
+ if ( null === self::$instance ) {
78
+ self::$instance = new self();
79
+ }
80
+ return self::$instance;
81
+ }
82
+
83
  /**
84
  * Check for default PHP zip support.
85
  *
422
  $zip = new \ZipArchive();
423
  $zipRes = $zip->open( $this->file );
424
  if ( $zipRes ) {
425
+ $content = $zip->getFromName( 'clone/config.txt' );
426
  $zip->close();
427
 
428
  return $content;
766
  return $data;
767
  }
768
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769
  }
class/class-mainwp-clone-page.php CHANGED
@@ -806,11 +806,11 @@ class MainWP_Clone_Page {
806
  return;
807
  }
808
  var str = arguments[0];
809
- var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
810
  var a = b = [], numSubstitutions = 0, numMatches = 0;
811
  while ( a = re.exec( str ) ) {
812
  var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
813
- var pPrecision = a[5], pType = a[6], rightPart = a[7];
814
 
815
  numMatches++;
816
  if ( pType == '%' ) {
806
  return;
807
  }
808
  var str = arguments[0];
809
+ var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(\d\$)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
810
  var a = b = [], numSubstitutions = 0, numMatches = 0;
811
  while ( a = re.exec( str ) ) {
812
  var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
813
+ var pPrecision = a[5], pOrder = a[6], pType = a[7], rightPart = a[8];
814
 
815
  numMatches++;
816
  if ( pType == '%' ) {
class/class-mainwp-clone.php CHANGED
@@ -202,6 +202,153 @@ class MainWP_Clone {
202
  return $mime_types;
203
  }
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  /**
206
  * Method clone_backup_create()
207
  *
@@ -365,11 +512,12 @@ class MainWP_Clone {
365
  $backupdir = $dirs[0];
366
  $dh = opendir( $backupdir );
367
  if ( $dh ) {
368
- $file = readdir( $dh );
369
- while ( false !== $file ) {
370
- if ( '.' !== $file && '..' !== $file && self::is_archive( $file, 'download-' ) ) {
371
- unlink( $backupdir . $file );
372
  }
 
373
  }
374
  closedir( $dh );
375
  }
@@ -549,7 +697,7 @@ class MainWP_Clone {
549
  * @return resource Return the backup file.
550
  */
551
  private function clone_backup_get_file( $file, &$testFull ) {
552
- if ( '' === $file ) {
553
  $dirs = MainWP_Helper::get_mainwp_dir( 'backup', false );
554
  $backupdir = $dirs[0];
555
  $files = glob( $backupdir . 'download-*' );
202
  return $mime_types;
203
  }
204
 
205
+ /**
206
+ * Request clone.
207
+ *
208
+ * @return bool|void true|void.
209
+ */
210
+ public function request_clone_funct() {
211
+
212
+ if ( ! isset( $_REQUEST['key'] ) ) {
213
+ return;
214
+ }
215
+ if ( ! isset( $_REQUEST['f'] ) || ( '' === $_REQUEST['f'] ) ) {
216
+ return;
217
+ }
218
+ if ( ! isset( $_REQUEST['key'] ) || ! MainWP_Connect::instance()->is_valid_auth( wp_unslash( $_REQUEST['key'] ) ) ) {
219
+ return;
220
+ }
221
+
222
+ $cloneFunc = isset( $_REQUEST['cloneFunc'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['cloneFunc'] ) ) : '';
223
+
224
+ if ( 'dl' === $cloneFunc ) {
225
+ $f = isset( $_REQUEST['f'] ) ? wp_unslash( $_REQUEST['f'] ) : '';
226
+ if ( ! empty( $f ) ) {
227
+ MainWP_Utility::instance()->upload_file( wp_unslash( $_REQUEST['f'] ) );
228
+ }
229
+ exit;
230
+ } elseif ( 'deleteCloneBackup' === $cloneFunc ) {
231
+ $dirs = MainWP_Helper::get_mainwp_dir( 'backup' );
232
+ $backupdir = $dirs[0];
233
+ $result = isset( $_POST['f'] ) ? glob( $backupdir . wp_unslash( $_POST['f'] ) ) : array();
234
+ if ( 0 === count( $result ) ) {
235
+ return;
236
+ }
237
+
238
+ unlink( $result[0] );
239
+ MainWP_Helper::write( array( 'result' => 'ok' ) );
240
+ } elseif ( 'createCloneBackupPoll' === $cloneFunc ) {
241
+ $dirs = MainWP_Helper::get_mainwp_dir( 'backup' );
242
+ $backupdir = $dirs[0];
243
+ $f = isset( $_POST['f'] ) ? wp_unslash( $_POST['f'] ) : '';
244
+ $archiveFile = false;
245
+ if ( ! empty( $f ) ) {
246
+ $result = glob( $backupdir . 'backup-' . $f . '-*' );
247
+ foreach ( $result as $file ) {
248
+ if ( self::is_archive( $file, 'backup-' . $f . '-' ) ) {
249
+ $archiveFile = $file;
250
+ break;
251
+ }
252
+ }
253
+ }
254
+ if ( false === $archiveFile ) {
255
+ return;
256
+ }
257
+
258
+ MainWP_Helper::write( array( 'size' => filesize( $archiveFile ) ) );
259
+ } elseif ( 'createCloneBackup' === $cloneFunc ) {
260
+ $this->create_clone_backup();
261
+ }
262
+ return true;
263
+ }
264
+
265
+
266
+ /**
267
+ * Create backup of clone.
268
+ */
269
+ private function create_clone_backup() { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.
270
+ MainWP_Helper::end_session();
271
+ $files = glob( WP_CONTENT_DIR . '/dbBackup*.sql' );
272
+ foreach ( $files as $file ) {
273
+ unlink( $file );
274
+ }
275
+ if ( file_exists( ABSPATH . 'clone/config.txt' ) ) {
276
+ unlink( ABSPATH . 'clone/config.txt' );
277
+ }
278
+ if ( MainWP_Helper::is_dir_empty( ABSPATH . 'clone' ) ) {
279
+ rmdir( ABSPATH . 'clone' );
280
+ }
281
+
282
+ $wpversion = isset( $_POST['wpversion'] ) ? sanitize_text_field( wp_unslash( $_POST['wpversion'] ) ) : '';
283
+ global $wp_version;
284
+ $includeCoreFiles = ( $wpversion !== $wp_version );
285
+ $excludes = ( isset( $_POST['exclude'] ) ? explode( ',', wp_unslash( $_POST['exclude'] ) ) : array() );
286
+ $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/uploads/mainwp';
287
+ $uploadDir = MainWP_Helper::get_mainwp_dir();
288
+ $uploadDir = $uploadDir[0];
289
+ $excludes[] = str_replace( ABSPATH, '', $uploadDir );
290
+ $excludes[] = str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '/object-cache.php';
291
+ if ( version_compare( phpversion(), '5.3.0' ) >= 0 || ! ini_get( 'safe_mode' ) ) {
292
+ set_time_limit( 6000 );
293
+ }
294
+
295
+ $newExcludes = array();
296
+ foreach ( $excludes as $exclude ) {
297
+ $newExcludes[] = rtrim( $exclude, '/' );
298
+ }
299
+
300
+ $method = ( ! isset( $_POST['zipmethod'] ) ? 'tar.gz' : wp_unslash( $_POST['zipmethod'] ) );
301
+ if ( 'tar.gz' === $method && ! function_exists( 'gzopen' ) ) {
302
+ $method = 'zip';
303
+ }
304
+
305
+ $file = false;
306
+ if ( isset( $_POST['f'] ) ) {
307
+ $file = ! empty( $_POST['f'] ) ? wp_unslash( $_POST['f'] ) : false;
308
+ } elseif ( isset( $_POST['file'] ) ) {
309
+ $file = ! empty( $_POST['file'] ) ? wp_unslash( $_POST['file'] ) : false;
310
+ }
311
+
312
+ $res = MainWP_Backup::get()->create_full_backup( $newExcludes, $file, true, $includeCoreFiles, 0, false, false, false, false, $method );
313
+ if ( ! $res ) {
314
+ $information['backup'] = false;
315
+ } else {
316
+ $information['backup'] = $res['file'];
317
+ $information['size'] = $res['filesize'];
318
+ }
319
+
320
+ $plugins = array();
321
+ $dir = WP_CONTENT_DIR . '/plugins/';
322
+ $fh = opendir( $dir );
323
+ while ( $entry = readdir( $fh ) ) {
324
+ if ( ! is_dir( $dir . $entry ) ) {
325
+ continue;
326
+ }
327
+ if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
328
+ continue;
329
+ }
330
+ $plugins[] = $entry;
331
+ }
332
+ closedir( $fh );
333
+ $information['plugins'] = $plugins;
334
+
335
+ $themes = array();
336
+ $dir = WP_CONTENT_DIR . '/themes/';
337
+ $fh = opendir( $dir );
338
+ while ( $entry = readdir( $fh ) ) {
339
+ if ( ! is_dir( $dir . $entry ) ) {
340
+ continue;
341
+ }
342
+ if ( ( '.' === $entry ) || ( '..' === $entry ) ) {
343
+ continue;
344
+ }
345
+ $themes[] = $entry;
346
+ }
347
+ closedir( $fh );
348
+ $information['themes'] = $themes;
349
+ MainWP_Helper::write( $information );
350
+ }
351
+
352
  /**
353
  * Method clone_backup_create()
354
  *
512
  $backupdir = $dirs[0];
513
  $dh = opendir( $backupdir );
514
  if ( $dh ) {
515
+ $fl = readdir( $dh );
516
+ while ( false !== $fl ) {
517
+ if ( '.' !== $fl && '..' !== $fl && self::is_archive( $fl, 'download-' ) ) {
518
+ unlink( $backupdir . $fl );
519
  }
520
+ $fl = readdir( $dh );
521
  }
522
  closedir( $dh );
523
  }
697
  * @return resource Return the backup file.
698
  */
699
  private function clone_backup_get_file( $file, &$testFull ) {
700
+ if ( '' == $file ) {
701
  $dirs = MainWP_Helper::get_mainwp_dir( 'backup', false );
702
  $backupdir = $dirs[0];
703
  $files = glob( $backupdir . 'download-*' );
class/class-mainwp-helper.php CHANGED
@@ -248,7 +248,9 @@ class MainWP_Helper {
248
  * @const ( string ) Defined file system method.
249
  * @source https://code-reference.mainwp.com/classes/MainWP.Child.MainWP_Helper.html
250
  */
251
- define( 'FS_METHOD', 'direct' );
 
 
252
  }
253
  $init = \WP_Filesystem( $creds );
254
  } else {
248
  * @const ( string ) Defined file system method.
249
  * @source https://code-reference.mainwp.com/classes/MainWP.Child.MainWP_Helper.html
250
  */
251
+ if ( ! defined( 'FS_METHOD' ) ) {
252
+ define( 'FS_METHOD', 'direct' );
253
+ }
254
  }
255
  $init = \WP_Filesystem( $creds );
256
  } else {
class/class-mainwp-utility.php CHANGED
@@ -290,14 +290,13 @@ class MainWP_Utility {
290
  return;
291
  }
292
  session_write_close();
293
- header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ), true );
294
- header( 'X-Robots-Tag: noindex, nofollow', true );
295
- header( 'X-MainWP-Child-Version: ' . MainWP_Child::$version, true );
296
- nocache_headers();
297
- if ( 'test' == $_GET['mainwp_child_run'] ) {
298
- die( 'MainWP Test' );
299
- }
300
- die( '' );
301
  }
302
 
303
 
290
  return;
291
  }
292
  session_write_close();
293
+ if ( ! headers_sent() ) {
294
+ header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ), true );
295
+ header( 'X-Robots-Tag: noindex, nofollow', true );
296
+ header( 'X-MainWP-Child-Version: ' . MainWP_Child::$version, true );
297
+ nocache_headers();
298
+ }
299
+ die( 'MainWP Test' );
 
300
  }
301
 
302
 
mainwp-child.php CHANGED
@@ -12,7 +12,7 @@
12
  * Author: MainWP
13
  * Author URI: https://mainwp.com
14
  * Text Domain: mainwp-child
15
- * Version: 4.1
16
  * Requires at least: 3.6
17
  * Requires PHP: 5.6
18
  */
12
  * Author: MainWP
13
  * Author URI: https://mainwp.com
14
  * Text Domain: mainwp-child
15
+ * Version: 4.1.1
16
  * Requires at least: 3.6
17
  * Requires PHP: 5.6
18
  */
readme.txt CHANGED
@@ -7,7 +7,7 @@ Plugin URI: https://mainwp.com
7
  Requires at least: 3.6
8
  Tested up to: 5.5.1
9
  Requires PHP: 5.6
10
- Stable tag: 4.1
11
  License: GPLv3 or later
12
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
13
 
@@ -79,6 +79,11 @@ ManageWP is a Service as a Solution (SaaS) property owned by Godaddy. The SaaS
79
 
80
  MainWP follows the tradition of WordPress and is [open source](https://github.com/mainwp/mainwp-child/), [private](https://mainwp.com/protect-your-data/), and [fully extendable](https://mainwp.dev/). . The fact that MainWP is open source and extendable means you have almost unlimited customization option, this allows you to run your WordPress management business as you see fit.
81
 
 
 
 
 
 
82
  = How do I customize MainWP for my needs? =
83
  If you want to make some basic changes to the look of your Dashboard, you can use our prebuilt [Custom Dashbboard](https://mainwp.com/extension/mainwp-custom-dashboard-extension/) Extension, or if you want to dig in and build Extensions, you can learn all about Extension creation at [MainWP.dev](https://mainwp.dev/)
84
 
@@ -102,6 +107,13 @@ Sure we have a quick FAQ with a lot more questions and answers [here](https://ma
102
 
103
  == Changelog ==
104
 
 
 
 
 
 
 
 
105
  = 4.1 - 9-9-20 =
106
  * Fixed: An issue with posting Custom Post Types
107
  * Fixed: Multiple PHP Warnings
7
  Requires at least: 3.6
8
  Tested up to: 5.5.1
9
  Requires PHP: 5.6
10
+ Stable tag: 4.1.1
11
  License: GPLv3 or later
12
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
13
 
79
 
80
  MainWP follows the tradition of WordPress and is [open source](https://github.com/mainwp/mainwp-child/), [private](https://mainwp.com/protect-your-data/), and [fully extendable](https://mainwp.dev/). . The fact that MainWP is open source and extendable means you have almost unlimited customization option, this allows you to run your WordPress management business as you see fit.
81
 
82
+ = How do I know my sites are secure using MainWP? =
83
+ We take security very seriously at MainWP. We welcome any peer review of our [100% open source code](https://github.com/mainwp/mainwp-child/) to ensure nobody's MainWP management system is ever compromised or hacked.
84
+
85
+ We also participate in the [HackerOne](https://www.hackerone.com) bug bounty program; this allows ethical hackers to review MainWP code and directly share any vulnerability information with us in return for a monetary reward.
86
+
87
  = How do I customize MainWP for my needs? =
88
  If you want to make some basic changes to the look of your Dashboard, you can use our prebuilt [Custom Dashbboard](https://mainwp.com/extension/mainwp-custom-dashboard-extension/) Extension, or if you want to dig in and build Extensions, you can learn all about Extension creation at [MainWP.dev](https://mainwp.dev/)
89
 
107
 
108
  == Changelog ==
109
 
110
+ = 4.1.1 - 10-7-20 =
111
+ * Fixed: An issue with creating new users
112
+ * Fixed: An issue with cloning sites
113
+ * Fixed: An issue with creating post tags
114
+ * Updated: Multiple database query improvements
115
+ * Preventative: Multiple security improvements
116
+
117
  = 4.1 - 9-9-20 =
118
  * Fixed: An issue with posting Custom Post Types
119
  * Fixed: Multiple PHP Warnings