Jetpack by WordPress.com - Version 4.2.1

Version Description

  • Release date: August 17th, 2016

Bug Fixes:

  • We fixed a conflict between Jetpack and W3 Total Cache.
  • We fixed some issues with Publicize and Custom Post Types.
  • Very large Multisite networks with lots of users can now be synchronized with WordPress.com.
  • We improved the synchronization process between your site and WordPress.com.
Download this release

Release Info

Developer samhotchkiss
Plugin Icon 128x128 Jetpack by WordPress.com
Version 4.2.1
Comparing to
See all releases

Code changes from version 4.2 to 4.2.1

changelog.txt CHANGED
@@ -1,5 +1,70 @@
1
  == Changelog ==
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  = 4.1 =
4
 
5
  * Release date: July 6th, 2016
1
  == Changelog ==
2
 
3
+ = 4.2.1 =
4
+
5
+ * Release date: August 17th, 2016
6
+
7
+ **Bug Fixes:**
8
+
9
+ * We fixed a conflict between Jetpack and W3 Total Cache.
10
+ * We fixed some issues with Publicize and Custom Post Types.
11
+ * Very large Multisite networks with lots of users can now be synchronized with WordPress.com.
12
+ * We improved the synchronization process between your site and WordPress.com.
13
+
14
+ = 4.2 =
15
+
16
+ * Release date: August 10th, 2016
17
+
18
+ **Performance Enhancements:**
19
+
20
+ * We’ve improved Jetpack’s performance by making calls to the database more efficient; essentially, Jetpack is doing less on each page load, making things faster. #4281, #4316
21
+ * We’ve ensured that every feature uses information that is up to date by completely refactoring the way information was synchronized between your site and WordPress.com.
22
+ * We've improved the way Jetpack queries for information about features, which results in less overall queries.
23
+
24
+ **Exciting Feature and UI Improvements:**
25
+
26
+ * We now track your visitor views of Carousel images in stats.
27
+ * You can now customize advanced typographic settings like ligatures in the Custom CSS editor with new support for the `font-feature-settings` property.
28
+ * We’ve improved the experience when you don’t actually have enough posts to Infinitely Scroll.
29
+ * Our Contact Info Widget allows you to enter a Google Maps API Key which is now required by Google if you want to display a map.
30
+
31
+ **Security:**
32
+
33
+ * We’re continuing our efforts to harden Jetpack security, by implementing the `hash_equals()` function to avoid timing attacks when comparing strings. We also improved security on CSVs exported from your contact form.
34
+
35
+ **Slightly Less Exciting Feature Improvements:**
36
+
37
+ * The Cartodb shortcode has been changed to match the new product name, Carto.
38
+ * The YouTube shortcode now uses the content width defined by the theme when available, even if an embed size was defined in an old version of WordPress.
39
+ * Breadcrumbs now support hierarchical post types and taxonomies.
40
+ * We’ve added the Portfolio Post Type to the WordPress.com REST API whitelist.
41
+ * There are a few new parameters for the Dailymotion shortcode.
42
+
43
+ **Improved Compatibility:**
44
+
45
+ * We now work well with WP Stagecoach staging sites, so you should not see any future impact on production sites.
46
+ * We had some PHP notices popping up in the WooCommerce plugin wizard screen, these are gone.
47
+
48
+ **Bug Fixes:**
49
+
50
+ * We stopped loading compatibility stylesheets on the default theme's singular views for Infinite Scroll.
51
+ * Debug tests forwarded through the contact form in the Jetpack Debug menu are now successfully sent to the support team.
52
+ * We’ve removed the PHP notices you might have seen when moderating comments.
53
+ * There are no longer PHP notices cropping up when publishing via Cron.
54
+ * We’ve fixed the official Sharing buttons so they now line up just right.
55
+ * The PHP warnings of Sitemaps stylesheets have been eliminated.
56
+ * We’ve done away with the warnings that appeared when Tonesque processes a file which claims to be one filetype, but is actually another.
57
+ * We’ve exterminated PHP notices that appeared when using Random Redirect, as well as when the author wasn't set.
58
+
59
+ = 4.1.1 =
60
+
61
+ * Release date: July 7th, 2016
62
+
63
+ **Bug Fixes:**
64
+
65
+ * SSO: Use high-resolution Gravatar images on the log-in form on Retina devices.
66
+ * Publicize: improve reliability of Publicize when publishing new posts.
67
+
68
  = 4.1 =
69
 
70
  * Release date: July 6th, 2016
class.jetpack.php CHANGED
@@ -1136,12 +1136,9 @@ class Jetpack {
1136
  * @return bool
1137
  */
1138
  public static function is_single_user_site() {
1139
- $user_query = new WP_User_Query( array(
1140
- 'blog_id' => get_current_blog_id(),
1141
- 'fields' => 'ID',
1142
- 'number' => 2
1143
- ) );
1144
- return 1 === (int) $user_query->get_total();
1145
  }
1146
 
1147
  /**
@@ -2893,17 +2890,23 @@ p {
2893
  /**
2894
  * Return stat data for WPCOM sync
2895
  */
2896
- function get_stat_data() {
2897
  $heartbeat_data = Jetpack_Heartbeat::generate_stats_array();
2898
- $additional_data = $this->get_additional_stat_data();
 
 
2899
 
2900
- return json_encode( array_merge( $heartbeat_data, $additional_data ) );
 
 
 
 
2901
  }
2902
 
2903
  /**
2904
  * Get additional stat data to sync to WPCOM
2905
  */
2906
- function get_additional_stat_data( $prefix = '' ) {
2907
  $return["{$prefix}themes"] = Jetpack::get_parsed_theme_data();
2908
  $return["{$prefix}plugins-extra"] = Jetpack::get_parsed_plugin_data();
2909
  $return["{$prefix}users"] = count_users();
1136
  * @return bool
1137
  */
1138
  public static function is_single_user_site() {
1139
+ global $wpdb;
1140
+ $some_users = $wpdb->get_var( "select count(*) from (select user_id from $wpdb->usermeta where meta_key = '{$wpdb->prefix}capabilities' LIMIT 2) as someusers" );
1141
+ return 1 === (int) $some_users;
 
 
 
1142
  }
1143
 
1144
  /**
2890
  /**
2891
  * Return stat data for WPCOM sync
2892
  */
2893
+ public static function get_stat_data( $encode = true ) {
2894
  $heartbeat_data = Jetpack_Heartbeat::generate_stats_array();
2895
+ $additional_data = self::get_additional_stat_data();
2896
+
2897
+ $merged_data = array_merge( $heartbeat_data, $additional_data );
2898
 
2899
+ if ( $encode ) {
2900
+ return json_encode( $merged_data );
2901
+ }
2902
+
2903
+ return $merged_data;
2904
  }
2905
 
2906
  /**
2907
  * Get additional stat data to sync to WPCOM
2908
  */
2909
+ public static function get_additional_stat_data( $prefix = '' ) {
2910
  $return["{$prefix}themes"] = Jetpack::get_parsed_theme_data();
2911
  $return["{$prefix}plugins-extra"] = Jetpack::get_parsed_plugin_data();
2912
  $return["{$prefix}users"] = count_users();
jetpack.php CHANGED
@@ -5,16 +5,16 @@
5
  * Plugin URI: http://jetpack.com
6
  * Description: Bring the power of the WordPress.com cloud to your self-hosted WordPress. Jetpack enables you to connect your blog to a WordPress.com account to use the powerful features normally only available to WordPress.com users.
7
  * Author: Automattic
8
- * Version: 4.2
9
  * Author URI: http://jetpack.com
10
  * License: GPL2+
11
  * Text Domain: jetpack
12
  * Domain Path: /languages/
13
  */
14
 
15
- define( 'JETPACK__MINIMUM_WP_VERSION', '4.4' );
16
 
17
- define( 'JETPACK__VERSION', '4.2' );
18
  define( 'JETPACK_MASTER_USER', true );
19
  define( 'JETPACK__API_VERSION', 1 );
20
  define( 'JETPACK__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
5
  * Plugin URI: http://jetpack.com
6
  * Description: Bring the power of the WordPress.com cloud to your self-hosted WordPress. Jetpack enables you to connect your blog to a WordPress.com account to use the powerful features normally only available to WordPress.com users.
7
  * Author: Automattic
8
+ * Version: 4.2.1
9
  * Author URI: http://jetpack.com
10
  * License: GPL2+
11
  * Text Domain: jetpack
12
  * Domain Path: /languages/
13
  */
14
 
15
+ define( 'JETPACK__MINIMUM_WP_VERSION', '4.5' );
16
 
17
+ define( 'JETPACK__VERSION', '4.2.1' );
18
  define( 'JETPACK_MASTER_USER', true );
19
  define( 'JETPACK__API_VERSION', 1 );
20
  define( 'JETPACK__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
json-endpoints/jetpack/class.jetpack-json-api-sync-endpoint.php CHANGED
@@ -20,7 +20,9 @@ class Jetpack_JSON_API_Sync_Endpoint extends Jetpack_JSON_API_Endpoint {
20
  }
21
 
22
  foreach ( array( 'posts', 'comments', 'users' ) as $module_name ) {
23
- if ( isset( $args[ $module_name ] ) ) {
 
 
24
  $ids = explode( ',', $args[ $module_name ] );
25
  if ( count( $ids ) > 0 ) {
26
  $modules[ $module_name ] = $ids;
@@ -32,9 +34,7 @@ class Jetpack_JSON_API_Sync_Endpoint extends Jetpack_JSON_API_Endpoint {
32
  $modules = null;
33
  }
34
 
35
- Jetpack_Sync_Actions::schedule_full_sync( $modules );
36
-
37
- return array( 'scheduled' => true );
38
  }
39
  }
40
 
@@ -156,6 +156,12 @@ class Jetpack_JSON_API_Sync_Modify_Settings_Endpoint extends Jetpack_JSON_API_Sy
156
  if ( is_numeric( $value ) ) {
157
  $value = (int) $value;
158
  }
 
 
 
 
 
 
159
  $sync_settings[ $key ] = $value;
160
  }
161
  }
20
  }
21
 
22
  foreach ( array( 'posts', 'comments', 'users' ) as $module_name ) {
23
+ if ( 'users' === $module_name && isset( $args[ $module_name ] ) && 'initial' === $args[ $module_name ] ) {
24
+ $modules[ 'users' ] = 'initial';
25
+ } elseif ( isset( $args[ $module_name ] ) ) {
26
  $ids = explode( ',', $args[ $module_name ] );
27
  if ( count( $ids ) > 0 ) {
28
  $modules[ $module_name ] = $ids;
34
  $modules = null;
35
  }
36
 
37
+ return array( 'scheduled' => Jetpack_Sync_Actions::schedule_full_sync( $modules ) );
 
 
38
  }
39
  }
40
 
156
  if ( is_numeric( $value ) ) {
157
  $value = (int) $value;
158
  }
159
+
160
+ // special case for sending empty arrays - a string with value 'empty'
161
+ if ( $value === 'empty' ) {
162
+ $value = array();
163
+ }
164
+
165
  $sync_settings[ $key ] = $value;
166
  }
167
  }
json-endpoints/jetpack/json-api-jetpack-endpoints.php CHANGED
@@ -655,13 +655,17 @@ new Jetpack_JSON_API_Sync_Histogram_Endpoint( array(
655
  ) );
656
 
657
  $sync_settings_response = array(
658
- 'dequeue_max_bytes' => '(int|bool=false) Maximum bytes to read from queue in a single request',
659
- 'sync_wait_time' => '(int|bool=false) Wait time between requests in seconds if sync threshold exceeded',
660
- 'sync_wait_threshold' => '(int|bool=false) If a request to WPCOM exceeds this duration, wait sync_wait_time seconds before sending again',
661
- 'upload_max_bytes' => '(int|bool=false) Maximum bytes to send in a single request',
662
- 'upload_max_rows' => '(int|bool=false) Maximum rows to send in a single request',
663
- 'max_queue_size' => '(int|bool=false) Maximum queue size that that the queue is allowed to expand to in DB rows to prevent the DB from filling up. Needs to also meet the max_queue_lag limit.',
664
- 'max_queue_lag' => '(int|bool=false) Maximum queue lag in seconds used to prevent the DB from filling up. Needs to also meet the max_queue_size limit.',
 
 
 
 
665
  );
666
 
667
  // GET /sites/%s/sync/settings
655
  ) );
656
 
657
  $sync_settings_response = array(
658
+ 'dequeue_max_bytes' => '(int|bool=false) Maximum bytes to read from queue in a single request',
659
+ 'sync_wait_time' => '(int|bool=false) Wait time between requests in seconds if sync threshold exceeded',
660
+ 'sync_wait_threshold' => '(int|bool=false) If a request to WPCOM exceeds this duration, wait sync_wait_time seconds before sending again',
661
+ 'upload_max_bytes' => '(int|bool=false) Maximum bytes to send in a single request',
662
+ 'upload_max_rows' => '(int|bool=false) Maximum rows to send in a single request',
663
+ 'max_queue_size' => '(int|bool=false) Maximum queue size that that the queue is allowed to expand to in DB rows to prevent the DB from filling up. Needs to also meet the max_queue_lag limit.',
664
+ 'max_queue_lag' => '(int|bool=false) Maximum queue lag in seconds used to prevent the DB from filling up. Needs to also meet the max_queue_size limit.',
665
+ 'queue_max_writes_sec' => '(int|bool=false) Maximum writes per second to allow to the queue during full sync.',
666
+ 'post_types_blacklist' => '(array|string|bool=false) List of post types to exclude from sync. Send "empty" to unset.',
667
+ 'meta_blacklist' => '(array|string|bool=false) List of meta keys to exclude from sync. Send "empty" to unset.',
668
+ 'disable' => '(int|bool=false) Set to 1 or true to disable sync entirely.',
669
  );
670
 
671
  // GET /sites/%s/sync/settings
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Jetpack by WordPress.com ===
2
  Contributors: automattic, adamkheckler, aduth, akirk, allendav, alternatekev, andy, annezazu, apeatling, azaozz, batmoo, barry, beaulebens, blobaugh, cainm, cena, cfinke, chaselivingston, chellycat, csonnek, danielbachhuber, davoraltman, daniloercoli, designsimply, dllh, drawmyface, dsmart, dzver, ebinnion, eliorivero, enej, eoigal, ethitter, gcorne, georgestephanis, gibrown, goldsounds, hew, hugobaeta, hypertextranch, iammattthomas, iandunn, jacobshere, jblz, jeherve, jenhooks, jenia, jgs, jkudish, jmdodd, Joen, johnjamesjacoby, jshreve, koke, kraftbj, lamdayap, lancewillett, lschuyler, macmanx, martinremy, matt, matveb, mattwiebe, maverick3x6, mcsf, mdawaffe, michael-arestad, migueluy, mikeyarce, mkaz, nancythanki, nickmomrik, obenland, pento, professor44, rachelsquirrel, rdcoll, ryancowles, richardmuscat, richardmtl, roccotripaldi, samhotchkiss, scarstocea, sdquirk, stefmattana, stephdau, tmoorewp, Viper007Bond, westi, yoavf, zinigor
3
  Tags: WordPress.com, jet pack, comments, contact, gallery, performance, sharing, security, shortcodes, stats, subscriptions, widgets
4
- Stable tag: 4.2
5
- Requires at least: 4.4
6
  Tested up to: 4.6
7
 
8
  Increase your traffic, view your stats, speed up your site, and protect yourself from hackers with Jetpack.
@@ -75,6 +75,17 @@ There are opportunities for developers at all levels to contribute. [Learn more
75
 
76
  == Changelog ==
77
 
 
 
 
 
 
 
 
 
 
 
 
78
  = 4.2 =
79
 
80
  * Release date: August 10th, 2016
1
  === Jetpack by WordPress.com ===
2
  Contributors: automattic, adamkheckler, aduth, akirk, allendav, alternatekev, andy, annezazu, apeatling, azaozz, batmoo, barry, beaulebens, blobaugh, cainm, cena, cfinke, chaselivingston, chellycat, csonnek, danielbachhuber, davoraltman, daniloercoli, designsimply, dllh, drawmyface, dsmart, dzver, ebinnion, eliorivero, enej, eoigal, ethitter, gcorne, georgestephanis, gibrown, goldsounds, hew, hugobaeta, hypertextranch, iammattthomas, iandunn, jacobshere, jblz, jeherve, jenhooks, jenia, jgs, jkudish, jmdodd, Joen, johnjamesjacoby, jshreve, koke, kraftbj, lamdayap, lancewillett, lschuyler, macmanx, martinremy, matt, matveb, mattwiebe, maverick3x6, mcsf, mdawaffe, michael-arestad, migueluy, mikeyarce, mkaz, nancythanki, nickmomrik, obenland, pento, professor44, rachelsquirrel, rdcoll, ryancowles, richardmuscat, richardmtl, roccotripaldi, samhotchkiss, scarstocea, sdquirk, stefmattana, stephdau, tmoorewp, Viper007Bond, westi, yoavf, zinigor
3
  Tags: WordPress.com, jet pack, comments, contact, gallery, performance, sharing, security, shortcodes, stats, subscriptions, widgets
4
+ Stable tag: 4.2.1
5
+ Requires at least: 4.5
6
  Tested up to: 4.6
7
 
8
  Increase your traffic, view your stats, speed up your site, and protect yourself from hackers with Jetpack.
75
 
76
  == Changelog ==
77
 
78
+ = 4.2.1 =
79
+
80
+ * Release date: August 17th, 2016
81
+
82
+ **Bug Fixes:**
83
+
84
+ * We fixed a conflict between Jetpack and W3 Total Cache.
85
+ * We fixed some issues with Publicize and Custom Post Types.
86
+ * Very large Multisite networks with lots of users can now be synchronized with WordPress.com.
87
+ * We improved the synchronization process between your site and WordPress.com.
88
+
89
  = 4.2 =
90
 
91
  * Release date: August 10th, 2016
sync/class.jetpack-sync-actions.php CHANGED
@@ -10,9 +10,10 @@ require_once dirname( __FILE__ ) . '/class.jetpack-sync-settings.php';
10
  class Jetpack_Sync_Actions {
11
  static $sender = null;
12
  static $listener = null;
 
13
 
14
  static function init() {
15
-
16
  // Add a custom "every minute" cron schedule
17
  add_filter( 'cron_schedules', array( __CLASS__, 'minute_cron_schedule' ) );
18
 
@@ -33,16 +34,13 @@ class Jetpack_Sync_Actions {
33
  return;
34
  }
35
 
 
 
 
36
  // cron hooks
37
- add_action( 'jetpack_sync_send_db_checksum', array( __CLASS__, 'send_db_checksum' ) );
38
  add_action( 'jetpack_sync_full', array( __CLASS__, 'do_full_sync' ), 10, 1 );
39
  add_action( 'jetpack_sync_cron', array( __CLASS__, 'do_cron_sync' ) );
40
 
41
- if ( ! wp_next_scheduled( 'jetpack_sync_send_db_checksum' ) ) {
42
- // Schedule a job to send DB checksums once an hour
43
- wp_schedule_event( time(), 'hourly', 'jetpack_sync_send_db_checksum' );
44
- }
45
-
46
  if ( ! wp_next_scheduled( 'jetpack_sync_cron' ) ) {
47
  // Schedule a job to send pending queue items once a minute
48
  wp_schedule_event( time(), '1min', 'jetpack_sync_cron' );
@@ -102,10 +100,18 @@ class Jetpack_Sync_Actions {
102
  }
103
 
104
  static function sync_allowed() {
105
- return ( Jetpack::is_active() && ! ( Jetpack::is_development_mode() || Jetpack::is_staging_site() ) )
106
  || defined( 'PHPUNIT_JETPACK_TESTSUITE' );
107
  }
108
 
 
 
 
 
 
 
 
 
109
  static function set_is_importing_true() {
110
  Jetpack_Sync_Settings::set_importing( true );
111
  }
@@ -136,20 +142,59 @@ class Jetpack_Sync_Actions {
136
  }
137
 
138
  static function schedule_initial_sync() {
139
- // we need this function call here because we have to run this function
140
  // reeeeally early in init, before WP_CRON_LOCK_TIMEOUT is defined.
141
  wp_functionality_constants();
142
- self::schedule_full_sync( array( 'options' => true, 'network_options' => true, 'functions' => true, 'constants' => true, 'users' => true ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
144
 
145
- static function schedule_full_sync( $modules = null ) {
 
 
 
 
 
 
 
 
146
  if ( $modules ) {
147
- wp_schedule_single_event( time() + 1, 'jetpack_sync_full', array( $modules ) );
148
  } else {
149
- wp_schedule_single_event( time() + 1, 'jetpack_sync_full' );
150
  }
151
 
152
- spawn_cron();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
154
 
155
  static function is_scheduled_full_sync( $modules = null ) {
@@ -161,7 +206,6 @@ class Jetpack_Sync_Actions {
161
  return true;
162
  }
163
  }
164
-
165
  return false;
166
  }
167
 
@@ -219,13 +263,6 @@ class Jetpack_Sync_Actions {
219
  } while ( $result );
220
  }
221
 
222
- static function send_db_checksum() {
223
- self::initialize_listener();
224
- self::initialize_sender();
225
- self::$sender->send_checksum();
226
- self::$sender->do_sync();
227
- }
228
-
229
  static function initialize_listener() {
230
  require_once dirname( __FILE__ ) . '/class.jetpack-sync-listener.php';
231
  self::$listener = Jetpack_Sync_Listener::get_instance();
10
  class Jetpack_Sync_Actions {
11
  static $sender = null;
12
  static $listener = null;
13
+ const INITIAL_SYNC_MULTISITE_INTERVAL = 10;
14
 
15
  static function init() {
16
+
17
  // Add a custom "every minute" cron schedule
18
  add_filter( 'cron_schedules', array( __CLASS__, 'minute_cron_schedule' ) );
19
 
34
  return;
35
  }
36
 
37
+ // publicize filter to prevent publicizing blacklisted post types
38
+ add_filter( 'publicize_should_publicize_published_post', array( __CLASS__, 'prevent_publicize_blacklisted_posts' ), 10, 2 );
39
+
40
  // cron hooks
 
41
  add_action( 'jetpack_sync_full', array( __CLASS__, 'do_full_sync' ), 10, 1 );
42
  add_action( 'jetpack_sync_cron', array( __CLASS__, 'do_cron_sync' ) );
43
 
 
 
 
 
 
44
  if ( ! wp_next_scheduled( 'jetpack_sync_cron' ) ) {
45
  // Schedule a job to send pending queue items once a minute
46
  wp_schedule_event( time(), '1min', 'jetpack_sync_cron' );
100
  }
101
 
102
  static function sync_allowed() {
103
+ return ( ! Jetpack_Sync_Settings::get_setting( 'disable' ) && Jetpack::is_active() && ! ( Jetpack::is_development_mode() || Jetpack::is_staging_site() ) )
104
  || defined( 'PHPUNIT_JETPACK_TESTSUITE' );
105
  }
106
 
107
+ static function prevent_publicize_blacklisted_posts( $should_publicize, $post ) {
108
+ if ( in_array( $post->post_type, Jetpack_Sync_Settings::get_setting( 'post_types_blacklist' ) ) ) {
109
+ return false;
110
+ }
111
+
112
+ return $should_publicize;
113
+ }
114
+
115
  static function set_is_importing_true() {
116
  Jetpack_Sync_Settings::set_importing( true );
117
  }
142
  }
143
 
144
  static function schedule_initial_sync() {
145
+ // we need this function call here because we have to run this function
146
  // reeeeally early in init, before WP_CRON_LOCK_TIMEOUT is defined.
147
  wp_functionality_constants();
148
+
149
+ if ( is_multisite() ) {
150
+ // stagger initial syncs for multisite blogs so they don't all pile on top of each other
151
+ $time_offset = ( rand() / getrandmax() ) * self::INITIAL_SYNC_MULTISITE_INTERVAL * get_blog_count();
152
+ } else {
153
+ $time_offset = 1;
154
+ }
155
+
156
+ self::schedule_full_sync(
157
+ array(
158
+ 'options' => true,
159
+ 'network_options' => true,
160
+ 'functions' => true,
161
+ 'constants' => true,
162
+ 'users' => 'initial'
163
+ ),
164
+ $time_offset
165
+ );
166
  }
167
 
168
+ static function schedule_full_sync( $modules = null, $time_offset = 1 ) {
169
+ if ( ! self::sync_allowed() ) {
170
+ return false;
171
+ }
172
+
173
+ if ( self::is_scheduled_full_sync() ) {
174
+ self::unschedule_all_full_syncs();
175
+ }
176
+
177
  if ( $modules ) {
178
+ wp_schedule_single_event( time() + $time_offset, 'jetpack_sync_full', array( $modules ) );
179
  } else {
180
+ wp_schedule_single_event( time() + $time_offset, 'jetpack_sync_full' );
181
  }
182
 
183
+ if ( $time_offset === 1 ) {
184
+ spawn_cron();
185
+ }
186
+
187
+ return true;
188
+ }
189
+
190
+ static function unschedule_all_full_syncs() {
191
+ foreach ( _get_cron_array() as $timestamp => $cron ) {
192
+ if ( ! empty( $cron['jetpack_sync_full'] ) ) {
193
+ foreach( $cron['jetpack_sync_full'] as $key => $config ) {
194
+ wp_unschedule_event( $timestamp, 'jetpack_sync_full', $config['args'] );
195
+ }
196
+ }
197
+ }
198
  }
199
 
200
  static function is_scheduled_full_sync( $modules = null ) {
206
  return true;
207
  }
208
  }
 
209
  return false;
210
  }
211
 
263
  } while ( $result );
264
  }
265
 
 
 
 
 
 
 
 
266
  static function initialize_listener() {
267
  require_once dirname( __FILE__ ) . '/class.jetpack-sync-listener.php';
268
  self::$listener = Jetpack_Sync_Listener::get_instance();
sync/class.jetpack-sync-defaults.php CHANGED
@@ -70,7 +70,6 @@ class Jetpack_Sync_Defaults {
70
  'comment_whitelist',
71
  'comment_max_links',
72
  'moderation_keys',
73
- 'blacklist_keys',
74
  'lang_id',
75
  'wga',
76
  'disabled_likes',
@@ -173,11 +172,6 @@ class Jetpack_Sync_Defaults {
173
  'option_value',
174
  );
175
 
176
- // returns escapted SQL that can be injected into a WHERE clause
177
- static function get_blacklisted_post_types_sql() {
178
- return 'post_type NOT IN (\'' . join( '\', \'', array_map( 'esc_sql', self::$blacklisted_post_types ) ) . '\')';
179
- }
180
-
181
  static $default_multisite_callable_whitelist = array(
182
  'network_name' => array( 'Jetpack', 'network_name' ),
183
  'network_allow_new_registrations' => array( 'Jetpack', 'network_allow_new_registrations' ),
@@ -203,6 +197,21 @@ class Jetpack_Sync_Defaults {
203
  '_wp_attachment_metadata',
204
  '_wp_page_template',
205
  '_publicize_twitter_user',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  );
207
 
208
  // TODO: move this to server? - these are theme support values
@@ -251,6 +260,10 @@ class Jetpack_Sync_Defaults {
251
  static $default_sync_wait_threshold = 5; // only wait before next send if the current send took more than X seconds
252
  static $default_max_queue_size = 1000;
253
  static $default_max_queue_lag = 900; // 15 minutes
 
 
 
 
254
  static $default_sync_callables_wait_time = MINUTE_IN_SECONDS; // seconds before sending callables again
255
  static $default_sync_constants_wait_time = HOUR_IN_SECONDS; // seconds before sending constants again
256
  }
70
  'comment_whitelist',
71
  'comment_max_links',
72
  'moderation_keys',
 
73
  'lang_id',
74
  'wga',
75
  'disabled_likes',
172
  'option_value',
173
  );
174
 
 
 
 
 
 
175
  static $default_multisite_callable_whitelist = array(
176
  'network_name' => array( 'Jetpack', 'network_name' ),
177
  'network_allow_new_registrations' => array( 'Jetpack', 'network_allow_new_registrations' ),
197
  '_wp_attachment_metadata',
198
  '_wp_page_template',
199
  '_publicize_twitter_user',
200
+ '_wp_trash_meta_comments_status',
201
+ );
202
+
203
+ static $default_blacklist_meta_keys = array(
204
+ 'post_views_count',
205
+ 'Views',
206
+ 'tve_leads_impressions',
207
+ 'views',
208
+ 'scc_share_count_crawldate',
209
+ 'wprss_last_update',
210
+ 'wprss_feed_is_updating',
211
+ 'snapFB',
212
+ 'syndication_item_hash',
213
+ 'phonenumber_spellings',
214
+ 'tmac_last_id'
215
  );
216
 
217
  // TODO: move this to server? - these are theme support values
260
  static $default_sync_wait_threshold = 5; // only wait before next send if the current send took more than X seconds
261
  static $default_max_queue_size = 1000;
262
  static $default_max_queue_lag = 900; // 15 minutes
263
+ static $default_queue_max_writes_sec = 100; // 100 rows a second
264
+ static $default_post_types_blacklist = array();
265
+ static $default_meta_blacklist = array();
266
+ static $default_disable = 0; // completely disable sending data to wpcom
267
  static $default_sync_callables_wait_time = MINUTE_IN_SECONDS; // seconds before sending callables again
268
  static $default_sync_constants_wait_time = HOUR_IN_SECONDS; // seconds before sending constants again
269
  }
sync/class.jetpack-sync-listener.php CHANGED
@@ -83,6 +83,10 @@ class Jetpack_Sync_Listener {
83
  // prevent adding items to the queue if it hasn't sent an item for 15 mins
84
  // AND the queue is over 1000 items long (by default)
85
  function can_add_to_queue( $queue ) {
 
 
 
 
86
  $state_transient_name = self::QUEUE_STATE_CHECK_TRANSIENT . '_' . $queue->id;
87
 
88
  $queue_state = get_transient( $state_transient_name );
@@ -109,6 +113,55 @@ class Jetpack_Sync_Listener {
109
  $this->enqueue_action( current_filter(), $args, $this->sync_queue );
110
  }
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  function enqueue_action( $current_filter, $args, $queue ) {
113
  /**
114
  * Modify or reject the data within an action before it is enqueued locally.
83
  // prevent adding items to the queue if it hasn't sent an item for 15 mins
84
  // AND the queue is over 1000 items long (by default)
85
  function can_add_to_queue( $queue ) {
86
+ if ( Jetpack_Sync_Settings::get_setting( 'disable' ) ) {
87
+ return false;
88
+ }
89
+
90
  $state_transient_name = self::QUEUE_STATE_CHECK_TRANSIENT . '_' . $queue->id;
91
 
92
  $queue_state = get_transient( $state_transient_name );
113
  $this->enqueue_action( current_filter(), $args, $this->sync_queue );
114
  }
115
 
116
+ // add many actions to the queue directly, without invoking them
117
+ function bulk_enqueue_full_sync_actions( $action_name, $args_array ) {
118
+ $queue = $this->get_full_sync_queue();
119
+
120
+ // periodically check the size of the queue, and disable adding to it if
121
+ // it exceeds some limit AND the oldest item exceeds the age limit (i.e. sending has stopped)
122
+ if ( ! $this->can_add_to_queue( $queue ) ) {
123
+ return;
124
+ }
125
+
126
+ // if we add any items to the queue, we should try to ensure that our script
127
+ // can't be killed before they are sent
128
+ if ( function_exists( 'ignore_user_abort' ) ) {
129
+ ignore_user_abort( true );
130
+ }
131
+
132
+ $data_to_enqueue = array();
133
+ $user_id = get_current_user_id();
134
+ $currtime = microtime( true );
135
+ $is_importing = Jetpack_Sync_Settings::is_importing();
136
+
137
+ foreach( $args_array as $args ) {
138
+
139
+ /**
140
+ * Modify or reject the data within an action before it is enqueued locally.
141
+ *
142
+ * @since 4.2.0
143
+ *
144
+ * @param array The action parameters
145
+ */
146
+ $args = apply_filters( "jetpack_sync_before_enqueue_$action_name", $args );
147
+
148
+ // allow listeners to abort
149
+ if ( $args === false ) {
150
+ continue;
151
+ }
152
+
153
+ $data_to_enqueue[] = array(
154
+ $action_name,
155
+ array( $args ),
156
+ $user_id,
157
+ $currtime,
158
+ $is_importing,
159
+ );
160
+ }
161
+
162
+ $queue->add_all( $data_to_enqueue );
163
+ }
164
+
165
  function enqueue_action( $current_filter, $args, $queue ) {
166
  /**
167
  * Modify or reject the data within an action before it is enqueued locally.
sync/class.jetpack-sync-module-callables.php CHANGED
@@ -98,18 +98,22 @@ class Jetpack_Sync_Module_Callables extends Jetpack_Sync_Module {
98
  }
99
 
100
  public function maybe_sync_callables() {
 
 
 
 
101
  if ( get_transient( self::CALLABLES_AWAIT_TRANSIENT_NAME ) ) {
102
  return;
103
  }
104
 
 
 
105
  $callables = $this->get_all_callables();
106
 
107
  if ( empty( $callables ) ) {
108
  return;
109
  }
110
 
111
- set_transient( self::CALLABLES_AWAIT_TRANSIENT_NAME, microtime( true ), Jetpack_Sync_Defaults::$default_sync_callables_wait_time );
112
-
113
  $callable_checksums = (array) get_option( self::CALLABLES_CHECKSUM_OPTION_NAME, array() );
114
 
115
  // only send the callables that have changed
98
  }
99
 
100
  public function maybe_sync_callables() {
101
+ if ( ! is_admin() || Jetpack_Sync_Settings::is_doing_cron() ) {
102
+ return;
103
+ }
104
+
105
  if ( get_transient( self::CALLABLES_AWAIT_TRANSIENT_NAME ) ) {
106
  return;
107
  }
108
 
109
+ set_transient( self::CALLABLES_AWAIT_TRANSIENT_NAME, microtime( true ), Jetpack_Sync_Defaults::$default_sync_callables_wait_time );
110
+
111
  $callables = $this->get_all_callables();
112
 
113
  if ( empty( $callables ) ) {
114
  return;
115
  }
116
 
 
 
117
  $callable_checksums = (array) get_option( self::CALLABLES_CHECKSUM_OPTION_NAME, array() );
118
 
119
  // only send the callables that have changed
sync/class.jetpack-sync-module-comments.php CHANGED
@@ -8,9 +8,11 @@ class Jetpack_Sync_Module_Comments extends Jetpack_Sync_Module {
8
 
9
  public function init_listeners( $callable ) {
10
  add_action( 'wp_insert_comment', $callable, 10, 2 );
11
- add_action( 'deleted_comment', $callable, 10 );
12
- add_action( 'trashed_comment', $callable, 10 );
13
- add_action( 'spammed_comment', $callable, 10 );
 
 
14
 
15
  // even though it's messy, we implement these hooks because
16
  // the edit_comment hook doesn't include the data
8
 
9
  public function init_listeners( $callable ) {
10
  add_action( 'wp_insert_comment', $callable, 10, 2 );
11
+ add_action( 'deleted_comment', $callable );
12
+ add_action( 'trashed_comment', $callable );
13
+ add_action( 'spammed_comment', $callable );
14
+ add_action( 'trashed_post_comments', $callable, 10, 2 );
15
+ add_action( 'untrash_post_comments', $callable );
16
 
17
  // even though it's messy, we implement these hooks because
18
  // the edit_comment hook doesn't include the data
sync/class.jetpack-sync-module-constants.php CHANGED
@@ -70,12 +70,13 @@ class Jetpack_Sync_Module_Constants extends Jetpack_Sync_Module {
70
  return;
71
  }
72
 
 
 
73
  $constants = $this->get_all_constants();
74
  if ( empty( $constants ) ) {
75
  return;
76
  }
77
 
78
- set_transient( self::CONSTANTS_AWAIT_TRANSIENT_NAME, microtime( true ), Jetpack_Sync_Defaults::$default_sync_constants_wait_time );
79
  $constants_checksums = (array) get_option( self::CONSTANTS_CHECKSUM_OPTION_NAME, array() );
80
 
81
  foreach ( $constants as $name => $value ) {
70
  return;
71
  }
72
 
73
+ set_transient( self::CONSTANTS_AWAIT_TRANSIENT_NAME, microtime( true ), Jetpack_Sync_Defaults::$default_sync_constants_wait_time );
74
+
75
  $constants = $this->get_all_constants();
76
  if ( empty( $constants ) ) {
77
  return;
78
  }
79
 
 
80
  $constants_checksums = (array) get_option( self::CONSTANTS_CHECKSUM_OPTION_NAME, array() );
81
 
82
  foreach ( $constants as $name => $value ) {
sync/class.jetpack-sync-module-full-sync.php CHANGED
@@ -18,6 +18,10 @@ class Jetpack_Sync_Module_Full_Sync extends Jetpack_Sync_Module {
18
  const STATUS_OPTION_PREFIX = 'jetpack_sync_full_';
19
  const FULL_SYNC_TIMEOUT = 3600;
20
 
 
 
 
 
21
  public function name() {
22
  return 'full-sync';
23
  }
@@ -40,6 +44,8 @@ class Jetpack_Sync_Module_Full_Sync extends Jetpack_Sync_Module {
40
  // remove all evidence of previous full sync items and status
41
  $this->reset_data();
42
 
 
 
43
  if ( $was_already_running ) {
44
  /**
45
  * Fires when a full sync is cancelled.
@@ -63,6 +69,11 @@ class Jetpack_Sync_Module_Full_Sync extends Jetpack_Sync_Module {
63
  $modules = array();
64
  }
65
 
 
 
 
 
 
66
  // by default, all modules are fully enabled
67
  if ( count( $modules ) === 0 ) {
68
  $default_module_config = true;
@@ -119,6 +130,8 @@ class Jetpack_Sync_Module_Full_Sync extends Jetpack_Sync_Module {
119
  */
120
  do_action( 'jetpack_full_sync_end', $store->checksum_all() );
121
 
 
 
122
  return true;
123
  }
124
 
@@ -238,4 +251,39 @@ class Jetpack_Sync_Module_Full_Sync extends Jetpack_Sync_Module {
238
  $prefix = self::STATUS_OPTION_PREFIX;
239
  update_option( "{$prefix}_{$name}", $value, false );
240
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  }
18
  const STATUS_OPTION_PREFIX = 'jetpack_sync_full_';
19
  const FULL_SYNC_TIMEOUT = 3600;
20
 
21
+ private $items_added_since_last_pause;
22
+ private $last_pause_time;
23
+ private $queue_rate_limit;
24
+
25
  public function name() {
26
  return 'full-sync';
27
  }
44
  // remove all evidence of previous full sync items and status
45
  $this->reset_data();
46
 
47
+ $this->enable_queue_rate_limit();
48
+
49
  if ( $was_already_running ) {
50
  /**
51
  * Fires when a full sync is cancelled.
69
  $modules = array();
70
  }
71
 
72
+ if ( isset( $modules['users'] ) && 'initial' === $modules['users'] ) {
73
+ $user_module = Jetpack_Sync_Modules::get_module( 'users' );
74
+ $modules['users'] = $user_module->get_initial_sync_user_config();
75
+ }
76
+
77
  // by default, all modules are fully enabled
78
  if ( count( $modules ) === 0 ) {
79
  $default_module_config = true;
130
  */
131
  do_action( 'jetpack_full_sync_end', $store->checksum_all() );
132
 
133
+ $this->disable_queue_rate_limit();
134
+
135
  return true;
136
  }
137
 
251
  $prefix = self::STATUS_OPTION_PREFIX;
252
  update_option( "{$prefix}_{$name}", $value, false );
253
  }
254
+
255
+ private function enable_queue_rate_limit() {
256
+ $this->queue_rate_limit = Jetpack_Sync_Settings::get_setting( 'queue_max_writes_sec' );
257
+ $this->items_added_since_last_pause = 0;
258
+ $this->last_pause_time = microtime( true );
259
+
260
+ add_action( 'jpsq_item_added', array( $this, 'queue_item_added' ) );
261
+ add_action( 'jpsq_items_added', array( $this, 'queue_items_added' ) );
262
+ }
263
+
264
+ private function disable_queue_rate_limit() {
265
+ remove_action( 'jpsq_item_added', array( $this, 'queue_item_added' ) );
266
+ remove_action( 'jpsq_items_added', array( $this, 'queue_items_added' ) );
267
+ }
268
+
269
+ public function queue_item_added() {
270
+ $this->queue_items_added( 1 );
271
+ }
272
+
273
+ public function queue_items_added( $item_count ) {
274
+ // jpsq_item_added and jpsq_items_added both exec 1 db query,
275
+ // so we ignore $item_count and treat it as always 1
276
+ $this->items_added_since_last_pause += 1;
277
+
278
+ if ( $this->items_added_since_last_pause > $this->queue_rate_limit ) {
279
+ // sleep for the rest of the second
280
+ $sleep_til = $this->last_pause_time + 1.0;
281
+ $sleep_duration = $sleep_til - microtime( true );
282
+ if ( $sleep_duration > 0.0 ) {
283
+ usleep( $sleep_duration * 1000000 );
284
+ $this->last_pause_time = microtime( true );
285
+ }
286
+ $this->items_added_since_last_pause = 0;
287
+ }
288
+ }
289
  }
sync/class.jetpack-sync-module-meta.php CHANGED
@@ -29,6 +29,10 @@ class Jetpack_Sync_Module_Meta extends Jetpack_Sync_Module {
29
  return false;
30
  }
31
 
 
 
 
 
32
  return $args;
33
  }
34
  }
29
  return false;
30
  }
31
 
32
+ if ( in_array( $args[2], Jetpack_Sync_Settings::get_setting( 'meta_blacklist' ) ) ) {
33
+ return false;
34
+ }
35
+
36
  return $args;
37
  }
38
  }
sync/class.jetpack-sync-module-posts.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
 
 
 
3
  class Jetpack_Sync_Module_Posts extends Jetpack_Sync_Module {
4
 
5
  public function name() {
@@ -43,7 +45,7 @@ class Jetpack_Sync_Module_Posts extends Jetpack_Sync_Module {
43
  }
44
 
45
  private function get_where_sql( $config ) {
46
- $where_sql = Jetpack_Sync_Defaults::get_blacklisted_post_types_sql();
47
 
48
  // config is a list of post IDs to sync
49
  if ( is_array( $config ) ) {
@@ -67,7 +69,8 @@ class Jetpack_Sync_Module_Posts extends Jetpack_Sync_Module {
67
 
68
  function filter_blacklisted_post_types( $args ) {
69
  $post = $args[1];
70
- if ( in_array( $post->post_type, Jetpack_Sync_Defaults::$blacklisted_post_types ) ) {
 
71
  return false;
72
  }
73
 
1
  <?php
2
 
3
+ require_once dirname( __FILE__ ) . '/class.jetpack-sync-settings.php';
4
+
5
  class Jetpack_Sync_Module_Posts extends Jetpack_Sync_Module {
6
 
7
  public function name() {
45
  }
46
 
47
  private function get_where_sql( $config ) {
48
+ $where_sql = Jetpack_Sync_Settings::get_blacklisted_post_types_sql();
49
 
50
  // config is a list of post IDs to sync
51
  if ( is_array( $config ) ) {
69
 
70
  function filter_blacklisted_post_types( $args ) {
71
  $post = $args[1];
72
+
73
+ if ( in_array( $post->post_type, Jetpack_Sync_Settings::get_setting( 'post_types_blacklist' ) ) ) {
74
  return false;
75
  }
76
 
sync/class.jetpack-sync-module-stats.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Jetpack_Sync_Module_Stats extends Jetpack_Sync_Module {
4
+
5
+ function name() {
6
+ return 'stats';
7
+ }
8
+
9
+ function init_listeners( $callback ) {
10
+ add_action( 'jetpack_heartbeat', array( $this, 'sync_site_stats' ), 20 );
11
+ add_action( 'jetpack_sync_heartbeat_stats', $callback );
12
+ }
13
+ /*
14
+ * This namespaces the action that we sync.
15
+ * So that we can differentiate it from future actions.
16
+ */
17
+ public function sync_site_stats() {
18
+ do_action( 'jetpack_sync_heartbeat_stats' );
19
+ }
20
+
21
+ public function init_before_send() {
22
+ add_filter( 'jetpack_sync_before_send_jetpack_sync_heartbeat_stats', array( $this, 'add_stats' ) );
23
+ }
24
+
25
+ public function add_stats() {
26
+ return array( Jetpack::get_stat_data( false ) );
27
+ }
28
+ }
sync/class.jetpack-sync-module-users.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
  class Jetpack_Sync_Module_Users extends Jetpack_Sync_Module {
 
 
4
  function name() {
5
  return 'users';
6
  }
@@ -51,6 +53,8 @@ class Jetpack_Sync_Module_Users extends Jetpack_Sync_Module {
51
  }
52
 
53
  public function sanitize_user( $user ) {
 
 
54
  unset( $user->data->user_pass );
55
 
56
  return $user;
@@ -144,28 +148,28 @@ class Jetpack_Sync_Module_Users extends Jetpack_Sync_Module {
144
  return;
145
  }
146
 
147
- $user = $this->sanitize_user( get_user_by( 'id', $user_id ) );
148
  if ( $meta_key === $user->cap_key ) {
149
  /**
150
  * Fires when the client needs to sync an updated user
151
  *
152
  * @since 4.2.0
153
  *
154
- * @param object The WP_User object
155
  */
156
- do_action( 'jetpack_sync_save_user', $user );
157
  }
158
  }
159
 
160
  public function enqueue_full_sync_actions( $config ) {
161
  global $wpdb;
162
- return $this->enqueue_all_ids_as_action( 'jetpack_full_sync_users', $wpdb->users, 'ID', $this->get_where_sql( $config ) );
163
  }
164
 
165
  public function estimate_full_sync_actions( $config ) {
166
  global $wpdb;
167
 
168
- $query = "SELECT count(*) FROM $wpdb->users";
169
 
170
  if ( $where_sql = $this->get_where_sql( $config ) ) {
171
  $query .= ' WHERE ' . $where_sql;
@@ -177,18 +181,34 @@ class Jetpack_Sync_Module_Users extends Jetpack_Sync_Module {
177
  }
178
 
179
  private function get_where_sql( $config ) {
 
 
 
 
180
  // config is a list of user IDs to sync
181
  if ( is_array( $config ) ) {
182
- return 'ID IN (' . implode( ',', array_map( 'intval', $config ) ) . ')';
183
  }
184
 
185
- return null;
186
  }
187
 
188
  function get_full_sync_actions() {
189
  return array( 'jetpack_full_sync_users' );
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  public function expand_users( $args ) {
193
  $user_ids = $args[0];
194
 
1
  <?php
2
 
3
  class Jetpack_Sync_Module_Users extends Jetpack_Sync_Module {
4
+ const MAX_INITIAL_SYNC_USERS = 100;
5
+
6
  function name() {
7
  return 'users';
8
  }
53
  }
54
 
55
  public function sanitize_user( $user ) {
56
+ // this create a new user object and stops the passing of the object by reference.
57
+ $user = unserialize( serialize( $user ) );
58
  unset( $user->data->user_pass );
59
 
60
  return $user;
148
  return;
149
  }
150
 
151
+ $user = get_user_by( 'id', $user_id );
152
  if ( $meta_key === $user->cap_key ) {
153
  /**
154
  * Fires when the client needs to sync an updated user
155
  *
156
  * @since 4.2.0
157
  *
158
+ * @param object The Sanitized WP_User object
159
  */
160
+ do_action( 'jetpack_sync_save_user', $this->sanitize_user( $user ) );
161
  }
162
  }
163
 
164
  public function enqueue_full_sync_actions( $config ) {
165
  global $wpdb;
166
+ return $this->enqueue_all_ids_as_action( 'jetpack_full_sync_users', $wpdb->usermeta, 'user_id', $this->get_where_sql( $config ) );
167
  }
168
 
169
  public function estimate_full_sync_actions( $config ) {
170
  global $wpdb;
171
 
172
+ $query = "SELECT count(*) FROM $wpdb->usermeta";
173
 
174
  if ( $where_sql = $this->get_where_sql( $config ) ) {
175
  $query .= ' WHERE ' . $where_sql;
181
  }
182
 
183
  private function get_where_sql( $config ) {
184
+ global $wpdb;
185
+
186
+ $query = "meta_key = '{$wpdb->prefix}capabilities'";
187
+
188
  // config is a list of user IDs to sync
189
  if ( is_array( $config ) ) {
190
+ $query .= ' AND user_id IN (' . implode( ',', array_map( 'intval', $config ) ) . ')';
191
  }
192
 
193
+ return $query;
194
  }
195
 
196
  function get_full_sync_actions() {
197
  return array( 'jetpack_full_sync_users' );
198
  }
199
 
200
+ function get_initial_sync_user_config() {
201
+ global $wpdb;
202
+
203
+ $user_ids = $wpdb->get_col( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '{$wpdb->prefix}user_level' AND meta_value > 0 LIMIT " . ( self::MAX_INITIAL_SYNC_USERS + 1 ) );
204
+
205
+ if ( count( $user_ids ) <= self::MAX_INITIAL_SYNC_USERS ) {
206
+ return $user_ids;
207
+ } else {
208
+ return false;
209
+ }
210
+ }
211
+
212
  public function expand_users( $args ) {
213
  $user_ids = $args[0];
214
 
sync/class.jetpack-sync-module.php CHANGED
@@ -65,22 +65,14 @@ abstract class Jetpack_Sync_Module {
65
  $page = 1;
66
  $chunk_count = 0;
67
  $previous_id = 0;
 
68
  while ( $ids = $wpdb->get_col( "SELECT {$id_field} FROM {$table_name} WHERE {$where_sql} AND {$id_field} > {$previous_id} ORDER BY {$id_field} ASC LIMIT {$items_per_page}" ) ) {
69
  // Request posts in groups of N for efficiency
70
  $chunked_ids = array_chunk( $ids, self::ARRAY_CHUNK_SIZE );
71
 
72
- // Send each chunk as an array of objects
73
- foreach ( $chunked_ids as $chunk ) {
74
- /**
75
- * Fires with a chunk of object IDs during full sync.
76
- * These are expanded to full objects before upload
77
- *
78
- * @since 4.2.0
79
- */
80
- do_action( $action_name, $chunk );
81
- $chunk_count ++;
82
- }
83
 
 
84
  $page += 1;
85
  $previous_id = end( $ids );
86
  }
65
  $page = 1;
66
  $chunk_count = 0;
67
  $previous_id = 0;
68
+ $listener = Jetpack_Sync_Listener::get_instance();
69
  while ( $ids = $wpdb->get_col( "SELECT {$id_field} FROM {$table_name} WHERE {$where_sql} AND {$id_field} > {$previous_id} ORDER BY {$id_field} ASC LIMIT {$items_per_page}" ) ) {
70
  // Request posts in groups of N for efficiency
71
  $chunked_ids = array_chunk( $ids, self::ARRAY_CHUNK_SIZE );
72
 
73
+ $listener->bulk_enqueue_full_sync_actions( $action_name, $chunked_ids );
 
 
 
 
 
 
 
 
 
 
74
 
75
+ $chunk_count += count( $chunked_ids );
76
  $page += 1;
77
  $previous_id = end( $ids );
78
  }
sync/class.jetpack-sync-queue.php CHANGED
@@ -54,6 +54,8 @@ class Jetpack_Sync_Queue {
54
  ) );
55
  $added = ( 0 !== $rows_added );
56
  }
 
 
57
  }
58
 
59
  // Attempts to insert all the items in a single SQL query. May be subject to query size limits!
@@ -76,6 +78,8 @@ class Jetpack_Sync_Queue {
76
  if ( count( $items ) === $rows_added ) {
77
  return new WP_Error( 'row_count_mismatch', "The number of rows inserted didn't match the size of the input array" );
78
  }
 
 
79
  }
80
 
81
  // Peek at the front-most item on the queue without checking it out
54
  ) );
55
  $added = ( 0 !== $rows_added );
56
  }
57
+
58
+ do_action( 'jpsq_item_added' );
59
  }
60
 
61
  // Attempts to insert all the items in a single SQL query. May be subject to query size limits!
78
  if ( count( $items ) === $rows_added ) {
79
  return new WP_Error( 'row_count_mismatch', "The number of rows inserted didn't match the size of the input array" );
80
  }
81
+
82
+ do_action( 'jpsq_items_added', $rows_added );
83
  }
84
 
85
  // Peek at the front-most item on the queue without checking it out
sync/class.jetpack-sync-sender.php CHANGED
@@ -128,6 +128,8 @@ class Jetpack_Sync_Sender {
128
  // we estimate the total encoded size as we go by encoding each item individually
129
  // this is expensive, but the only way to really know :/
130
  foreach ( $items as $key => $item ) {
 
 
131
  /**
132
  * Modify the data within an action before it is serialized and sent to the server
133
  * For example, during full sync this expands Post ID's into full Post objects,
@@ -139,7 +141,7 @@ class Jetpack_Sync_Sender {
139
  * @param int The ID of the user who triggered the action
140
  */
141
  $item[1] = apply_filters( 'jetpack_sync_before_send_' . $item[0], $item[1], $item[2] );
142
-
143
  if ( $item[1] === false ) {
144
  $skipped_items_ids[] = $key;
145
  continue;
@@ -315,8 +317,5 @@ class Jetpack_Sync_Sender {
315
 
316
  // clear the sync cron.
317
  wp_clear_scheduled_hook( 'jetpack_sync_cron' );
318
-
319
- // clear the checksum cron
320
- wp_clear_scheduled_hook( 'jetpack_send_db_checksum' );
321
  }
322
  }
128
  // we estimate the total encoded size as we go by encoding each item individually
129
  // this is expensive, but the only way to really know :/
130
  foreach ( $items as $key => $item ) {
131
+ // Suspending cache addition help prevent overloading in memory cache of large sites.
132
+ wp_suspend_cache_addition( true );
133
  /**
134
  * Modify the data within an action before it is serialized and sent to the server
135
  * For example, during full sync this expands Post ID's into full Post objects,
141
  * @param int The ID of the user who triggered the action
142
  */
143
  $item[1] = apply_filters( 'jetpack_sync_before_send_' . $item[0], $item[1], $item[2] );
144
+ wp_suspend_cache_addition( false );
145
  if ( $item[1] === false ) {
146
  $skipped_items_ids[] = $key;
147
  continue;
317
 
318
  // clear the sync cron.
319
  wp_clear_scheduled_hook( 'jetpack_sync_cron' );
 
 
 
320
  }
321
  }
sync/class.jetpack-sync-settings.php CHANGED
@@ -6,16 +6,23 @@ class Jetpack_Sync_Settings {
6
  const SETTINGS_OPTION_PREFIX = 'jetpack_sync_settings_';
7
 
8
  static $valid_settings = array(
9
- 'dequeue_max_bytes' => true,
10
- 'upload_max_bytes' => true,
11
- 'upload_max_rows' => true,
12
- 'sync_wait_time' => true,
13
- 'sync_wait_threshold' => true,
14
- 'max_queue_size' => true,
15
- 'max_queue_lag' => true,
 
 
 
 
16
  );
17
 
18
  static $is_importing;
 
 
 
19
 
20
  static function get_settings() {
21
  $settings = array();
@@ -33,6 +40,10 @@ class Jetpack_Sync_Settings {
33
  return false;
34
  }
35
 
 
 
 
 
36
  $value = get_option( self::SETTINGS_OPTION_PREFIX . $setting );
37
 
38
  if ( false === $value ) {
@@ -41,23 +52,54 @@ class Jetpack_Sync_Settings {
41
  update_option( self::SETTINGS_OPTION_PREFIX . $setting, $value, true );
42
  }
43
 
44
- return (int) $value;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
46
 
47
  static function update_settings( $new_settings ) {
48
  $validated_settings = array_intersect_key( $new_settings, self::$valid_settings );
49
  foreach ( $validated_settings as $setting => $value ) {
50
  update_option( self::SETTINGS_OPTION_PREFIX . $setting, $value, true );
 
 
 
 
 
 
 
 
 
51
  }
52
  }
53
 
 
 
 
 
 
54
  static function reset_data() {
55
- $valid_settings = self::$valid_settings;
56
- $settings_prefix = self::SETTINGS_OPTION_PREFIX;
57
  foreach ( $valid_settings as $option => $value ) {
58
- delete_option( $settings_prefix . $option );
59
  }
60
  self::set_importing( null );
 
61
  }
62
 
63
  static function set_importing( $is_importing ) {
@@ -72,4 +114,17 @@ class Jetpack_Sync_Settings {
72
 
73
  return defined( 'WP_IMPORTING' ) && WP_IMPORTING;
74
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
6
  const SETTINGS_OPTION_PREFIX = 'jetpack_sync_settings_';
7
 
8
  static $valid_settings = array(
9
+ 'dequeue_max_bytes' => true,
10
+ 'upload_max_bytes' => true,
11
+ 'upload_max_rows' => true,
12
+ 'sync_wait_time' => true,
13
+ 'sync_wait_threshold' => true,
14
+ 'max_queue_size' => true,
15
+ 'max_queue_lag' => true,
16
+ 'queue_max_writes_sec' => true,
17
+ 'post_types_blacklist' => true,
18
+ 'meta_blacklist' => true,
19
+ 'disable' => true,
20
  );
21
 
22
  static $is_importing;
23
+ static $is_doing_cron;
24
+
25
+ static $settings_cache = array(); // some settings can be expensive to compute - let's cache them
26
 
27
  static function get_settings() {
28
  $settings = array();
40
  return false;
41
  }
42
 
43
+ if ( isset( self::$settings_cache[ $setting ] ) ) {
44
+ return self::$settings_cache[ $setting ];
45
+ }
46
+
47
  $value = get_option( self::SETTINGS_OPTION_PREFIX . $setting );
48
 
49
  if ( false === $value ) {
52
  update_option( self::SETTINGS_OPTION_PREFIX . $setting, $value, true );
53
  }
54
 
55
+ if ( is_numeric( $value ) ) {
56
+ $value = intval( $value );
57
+ }
58
+
59
+ // specifically for the post_types blacklist, we want to include the hardcoded settings
60
+ if ( $setting === 'post_types_blacklist' ) {
61
+ $value = array_unique( array_merge( $value, Jetpack_Sync_Defaults::$blacklisted_post_types ) );
62
+ }
63
+
64
+ // ditto for meta blacklist
65
+ if ( $setting === 'meta_blacklist' ) {
66
+ $value = array_unique( array_merge( $value, Jetpack_Sync_Defaults::$default_blacklist_meta_keys ) );
67
+ }
68
+
69
+ self::$settings_cache[ $setting ] = $value;
70
+
71
+ return $value;
72
  }
73
 
74
  static function update_settings( $new_settings ) {
75
  $validated_settings = array_intersect_key( $new_settings, self::$valid_settings );
76
  foreach ( $validated_settings as $setting => $value ) {
77
  update_option( self::SETTINGS_OPTION_PREFIX . $setting, $value, true );
78
+ unset( self::$settings_cache[ $setting ] );
79
+
80
+ // if we set the disabled option to true, clear the queues
81
+ if ( 'disable' === $setting && !! $value ) {
82
+ require_once dirname( __FILE__ ) . '/class.jetpack-sync-listener.php';
83
+ $listener = Jetpack_Sync_Listener::get_instance();
84
+ $listener->get_sync_queue()->reset();
85
+ $listener->get_full_sync_queue()->reset();
86
+ }
87
  }
88
  }
89
 
90
+ // returns escapted SQL that can be injected into a WHERE clause
91
+ static function get_blacklisted_post_types_sql() {
92
+ return 'post_type NOT IN (\'' . join( '\', \'', array_map( 'esc_sql', self::get_setting( 'post_types_blacklist' ) ) ) . '\')';
93
+ }
94
+
95
  static function reset_data() {
96
+ $valid_settings = self::$valid_settings;
97
+ self::$settings_cache = array();
98
  foreach ( $valid_settings as $option => $value ) {
99
+ delete_option( self::SETTINGS_OPTION_PREFIX . $option );
100
  }
101
  self::set_importing( null );
102
+ self::set_doing_cron( null );
103
  }
104
 
105
  static function set_importing( $is_importing ) {
114
 
115
  return defined( 'WP_IMPORTING' ) && WP_IMPORTING;
116
  }
117
+
118
+ static function set_doing_cron( $is_doing_cron ) {
119
+ // set to NULL to revert to WP_IMPORTING, the standard behaviour
120
+ self::$is_doing_cron = $is_doing_cron;
121
+ }
122
+
123
+ static function is_doing_cron() {
124
+ if ( ! is_null( self::$is_doing_cron ) ) {
125
+ return self::$is_doing_cron;
126
+ }
127
+
128
+ return defined( 'DOING_CRON' ) && DOING_CRON;
129
+ }
130
  }
sync/class.jetpack-sync-wp-replicastore.php CHANGED
@@ -145,7 +145,7 @@ class Jetpack_Sync_WP_Replicastore implements iJetpack_Sync_Replicastore {
145
 
146
  public function posts_checksum( $min_id = null, $max_id = null ) {
147
  global $wpdb;
148
- return $this->table_checksum( $wpdb->posts, Jetpack_Sync_Defaults::$default_post_checksum_columns , 'ID', Jetpack_Sync_Defaults::get_blacklisted_post_types_sql(), $min_id, $max_id );
149
  }
150
 
151
  public function comment_count( $status = null, $min_id = null, $max_id = null ) {
@@ -267,6 +267,14 @@ class Jetpack_Sync_WP_Replicastore implements iJetpack_Sync_Replicastore {
267
  wp_spam_comment( $comment_id );
268
  }
269
 
 
 
 
 
 
 
 
 
270
  public function comments_checksum( $min_id = null, $max_id = null ) {
271
  global $wpdb;
272
  return $this->table_checksum( $wpdb->comments, Jetpack_Sync_Defaults::$default_comment_checksum_columns, 'comment_ID', "comment_approved <> 'spam'", $min_id, $max_id );
145
 
146
  public function posts_checksum( $min_id = null, $max_id = null ) {
147
  global $wpdb;
148
+ return $this->table_checksum( $wpdb->posts, Jetpack_Sync_Defaults::$default_post_checksum_columns , 'ID', Jetpack_Sync_Settings::get_blacklisted_post_types_sql(), $min_id, $max_id );
149
  }
150
 
151
  public function comment_count( $status = null, $min_id = null, $max_id = null ) {
267
  wp_spam_comment( $comment_id );
268
  }
269
 
270
+ public function trashed_post_comments( $post_id, $statuses ) {
271
+ wp_trash_post_comments( $post_id );
272
+ }
273
+
274
+ public function untrashed_post_comments( $post_id ) {
275
+ wp_untrash_post_comments( $post_id );
276
+ }
277
+
278
  public function comments_checksum( $min_id = null, $max_id = null ) {
279
  global $wpdb;
280
  return $this->table_checksum( $wpdb->comments, Jetpack_Sync_Defaults::$default_comment_checksum_columns, 'comment_ID', "comment_approved <> 'spam'", $min_id, $max_id );
sync/interface.jetpack-sync-replicastore.php CHANGED
@@ -47,6 +47,10 @@ interface iJetpack_Sync_Replicastore {
47
 
48
  public function delete_comment( $comment_id );
49
 
 
 
 
 
50
  public function comments_checksum( $min_id = null, $max_id = null );
51
 
52
  // options
47
 
48
  public function delete_comment( $comment_id );
49
 
50
+ public function trashed_post_comments( $post_id, $statuses );
51
+
52
+ public function untrashed_post_comments( $post_id );
53
+
54
  public function comments_checksum( $min_id = null, $max_id = null );
55
 
56
  // options