Jetpack by WordPress.com - Version 3.3.4

Version Description

Release Date: May 26, 2016

  • Important security update. Please upgrade immediately.
Download this release

Release Info

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

Code changes from version 3.2.3 to 3.3.4

Files changed (61) hide show
  1. class.jetpack-admin.php +2 -2
  2. class.jetpack-debugger.php +1 -1
  3. class.jetpack-heartbeat.php +29 -1
  4. class.jetpack-modules-list-table.php +6 -0
  5. class.jetpack-options.php +5 -1
  6. class.jetpack-post-images.php +5 -0
  7. class.jetpack-sync.php +23 -1
  8. class.jetpack-twitter-cards.php +13 -1
  9. class.jetpack.php +386 -75
  10. class.json-api-endpoints.php +200 -27
  11. class.json-api.php +17 -28
  12. class.media-extractor.php +1 -0
  13. class.media-summary.php +5 -7
  14. class.photon.php +24 -1
  15. css/jetpack-admin-rtl.css +54 -31
  16. css/jetpack-admin-rtl.min.css +1 -1
  17. css/jetpack-admin.css +37 -14
  18. css/jetpack-admin.css.map +1 -1
  19. css/jetpack-admin.min.css +1 -1
  20. css/jetpack-admin.min.css.map +1 -1
  21. css/jetpack-banners-rtl.css +151 -213
  22. css/jetpack-banners-rtl.min.css +1 -1
  23. css/jetpack-banners.css +150 -212
  24. css/jetpack-banners.css.map +1 -1
  25. css/jetpack-banners.min.css +1 -1
  26. css/jetpack-banners.min.css.map +1 -1
  27. css/jetpack-icons.css +1 -1
  28. css/jetpack-icons.css.map +1 -1
  29. css/jetpack-icons.min.css +1 -1
  30. css/jetpack-icons.min.css.map +1 -1
  31. css/jetpack-rtl.css +1 -1
  32. css/jetpack.css +1 -1
  33. functions.gallery.php +12 -0
  34. functions.opengraph.php +11 -1
  35. jetpack.php +2 -2
  36. json-endpoints.php +1182 -142
  37. json-endpoints/class.wpcom-json-api-get-post-v1-1-endpoint.php +28 -0
  38. json-endpoints/class.wpcom-json-api-get-site-endpoint.php +79 -1
  39. json-endpoints/class.wpcom-json-api-list-comments-endpoint.php +16 -43
  40. json-endpoints/class.wpcom-json-api-list-posts-endpoint.php +24 -4
  41. json-endpoints/class.wpcom-json-api-list-posts-v1-1-endpoint.php +370 -0
  42. json-endpoints/class.wpcom-json-api-post-endpoint.php +46 -7
  43. json-endpoints/class.wpcom-json-api-post-v1-1-endpoint.php +621 -0
  44. json-endpoints/class.wpcom-json-api-publicize-endpoint.php +4 -1
  45. json-endpoints/class.wpcom-json-api-sharing-buttons-endpoint.php +270 -0
  46. json-endpoints/class.wpcom-json-api-site-settings-endpoint.php +123 -43
  47. json-endpoints/class.wpcom-json-api-update-media-v1-1-endpoint.php +2 -2
  48. json-endpoints/class.wpcom-json-api-update-post-endpoint.php +30 -0
  49. json-endpoints/class.wpcom-json-api-update-post-v1-1-endpoint.php +617 -0
  50. json-endpoints/class.wpcom-json-api-upload-media-v1-1-endpoint.php +9 -114
  51. json-endpoints/jetpack/class.jetpack-json-api-core-modify-endpoint.php +1 -1
  52. json-endpoints/jetpack/class.jetpack-json-api-endpoint.php +5 -0
  53. json-endpoints/jetpack/class.jetpack-json-api-plugins-endpoint.php +35 -29
  54. json-endpoints/jetpack/class.jetpack-json-api-plugins-install-endpoint.php +2 -2
  55. json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php +48 -5
  56. json-endpoints/jetpack/class.jetpack-json-api-themes-delete-endpoint.php +41 -0
  57. json-endpoints/jetpack/class.jetpack-json-api-themes-install-endpoint.php +82 -0
  58. json-endpoints/jetpack/class.jetpack-json-api-updates-status-endpoint.php +8 -0
  59. json-endpoints/jetpack/json-api-jetpack-endpoints.php +45 -21
  60. languages/jetpack-ar.mo +0 -0
  61. languages/jetpack-ar.po +2259 -2138
class.jetpack-admin.php CHANGED
@@ -62,14 +62,14 @@ class Jetpack_Admin {
62
  $available_modules = $this->jetpack->get_available_modules();
63
  $active_modules = $this->jetpack->get_active_modules();
64
  $modules = array();
65
-
66
  foreach ( $available_modules as $module ) {
67
  if ( $module_array = $this->jetpack->get_module( $module ) ) {
68
  $short_desc = apply_filters( 'jetpack_short_module_description', $module_array['description'], $module );
69
  $short_desc_trunc = ( strlen( $short_desc ) > 143 ) ? substr( $short_desc, 0, 140 ) . '...' : $short_desc;
70
 
71
  $module_array['module'] = $module;
72
- $module_array['activated'] = in_array( $module, $active_modules );
73
  $module_array['deactivate_nonce'] = wp_create_nonce( 'jetpack_deactivate-' . $module );
74
  $module_array['activate_nonce'] = wp_create_nonce( 'jetpack_activate-' . $module );
75
  $module_array['available'] = self::is_module_available( $module_array );
62
  $available_modules = $this->jetpack->get_available_modules();
63
  $active_modules = $this->jetpack->get_active_modules();
64
  $modules = array();
65
+ $jetpack_active = Jetpack::is_active() || Jetpack::is_development_mode();
66
  foreach ( $available_modules as $module ) {
67
  if ( $module_array = $this->jetpack->get_module( $module ) ) {
68
  $short_desc = apply_filters( 'jetpack_short_module_description', $module_array['description'], $module );
69
  $short_desc_trunc = ( strlen( $short_desc ) > 143 ) ? substr( $short_desc, 0, 140 ) . '...' : $short_desc;
70
 
71
  $module_array['module'] = $module;
72
+ $module_array['activated'] = ( $jetpack_active ? in_array( $module, $active_modules ) : false );
73
  $module_array['deactivate_nonce'] = wp_create_nonce( 'jetpack_deactivate-' . $module );
74
  $module_array['activate_nonce'] = wp_create_nonce( 'jetpack_activate-' . $module );
75
  $module_array['available'] = self::is_module_available( $module_array );
class.jetpack-debugger.php CHANGED
@@ -202,7 +202,7 @@ class Jetpack_Debugger {
202
 
203
  <div id="blog_div" class="formbox">
204
  <div id="submit_div" class="contact-support">
205
- <input type="submit" name="submit" value="Contact Support">
206
  </div>
207
  </div>
208
  <div style="clear: both;"></div>
202
 
203
  <div id="blog_div" class="formbox">
204
  <div id="submit_div" class="contact-support">
205
+ <input type="submit" name="submit" value="<?php esc_html_e( 'Submit &#187;', 'jetpack' ); ?>">
206
  </div>
207
  </div>
208
  <div style="clear: both;"></div>
class.jetpack-heartbeat.php CHANGED
@@ -51,7 +51,7 @@ class Jetpack_Heartbeat {
51
 
52
  add_filter( 'jetpack_xmlrpc_methods', array( __CLASS__, 'jetpack_xmlrpc_methods' ) );
53
  }
54
-
55
  /**
56
  * Method that gets executed on the wp-cron call
57
  *
@@ -90,6 +90,8 @@ class Jetpack_Heartbeat {
90
  Jetpack_Options::update_option( 'last_heartbeat', time() );
91
 
92
  $jetpack->do_stats( 'server_side' );
 
 
93
  }
94
 
95
  public static function generate_stats_array( $prefix = '' ) {
@@ -101,6 +103,7 @@ class Jetpack_Heartbeat {
101
  $return["{$prefix}branch"] = floatval( JETPACK__VERSION );
102
  $return["{$prefix}wp-branch"] = floatval( get_bloginfo( 'version' ) );
103
  $return["{$prefix}php-branch"] = floatval( PHP_VERSION );
 
104
  $return["{$prefix}ssl"] = Jetpack::permit_ssl();
105
  $return["{$prefix}language"] = get_bloginfo( 'language' );
106
  $return["{$prefix}charset"] = get_bloginfo( 'charset' );
@@ -108,6 +111,31 @@ class Jetpack_Heartbeat {
108
  $return["{$prefix}identitycrisis"] = Jetpack::check_identity_crisis( 1 ) ? 'yes' : 'no';
109
  $return["{$prefix}plugins"] = implode( ',', Jetpack::get_active_plugins() );
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  if ( ! empty( $_SERVER['SERVER_ADDR'] ) || ! empty( $_SERVER['LOCAL_ADDR'] ) ) {
112
  $ip = ! empty( $_SERVER['SERVER_ADDR'] ) ? $_SERVER['SERVER_ADDR'] : $_SERVER['LOCAL_ADDR'];
113
  $ip_arr = array_map( 'intval', explode( '.', $ip ) );
51
 
52
  add_filter( 'jetpack_xmlrpc_methods', array( __CLASS__, 'jetpack_xmlrpc_methods' ) );
53
  }
54
+
55
  /**
56
  * Method that gets executed on the wp-cron call
57
  *
90
  Jetpack_Options::update_option( 'last_heartbeat', time() );
91
 
92
  $jetpack->do_stats( 'server_side' );
93
+
94
+ do_action( 'jetpack_heartbeat' );
95
  }
96
 
97
  public static function generate_stats_array( $prefix = '' ) {
103
  $return["{$prefix}branch"] = floatval( JETPACK__VERSION );
104
  $return["{$prefix}wp-branch"] = floatval( get_bloginfo( 'version' ) );
105
  $return["{$prefix}php-branch"] = floatval( PHP_VERSION );
106
+ $return["{$prefix}public"] = Jetpack_Options::get_option( 'public' );
107
  $return["{$prefix}ssl"] = Jetpack::permit_ssl();
108
  $return["{$prefix}language"] = get_bloginfo( 'language' );
109
  $return["{$prefix}charset"] = get_bloginfo( 'charset' );
111
  $return["{$prefix}identitycrisis"] = Jetpack::check_identity_crisis( 1 ) ? 'yes' : 'no';
112
  $return["{$prefix}plugins"] = implode( ',', Jetpack::get_active_plugins() );
113
 
114
+ switch ( Jetpack_Options::get_option( 'json_api_full_management', null ) ) {
115
+ case null:
116
+ $return["{$prefix}full_manage"] = 'unset';
117
+ break;
118
+ case false:
119
+ $return["{$prefix}full_manage"] = 'false';
120
+ break;
121
+ case true:
122
+ $return["{$prefix}full_manage"] = 'true';
123
+ break;
124
+ default:
125
+ $return["{$prefix}full_manage"] = Jetpack_Options::get_option( 'json_api_full_management', null );
126
+ }
127
+
128
+ if ( ! Jetpack_Options::get_option( 'public' ) ) {
129
+ // Also flag things as private since we don't provide the user with option to easy opt into if the site is private
130
+ $return["{$prefix}full_manage"] = 'private-' . $return["{$prefix}full_manage"];
131
+ }
132
+
133
+ // is-multi-network can have three values, `single-site`, `single-network`, and `multi-network`
134
+ $return["{$prefix}is-multi-network"] = 'single-site';
135
+ if ( is_multisite() ) {
136
+ $return["{$prefix}is-multi-network"] = Jetpack::is_multi_network() ? 'multi-network' : 'single-network';
137
+ }
138
+
139
  if ( ! empty( $_SERVER['SERVER_ADDR'] ) || ! empty( $_SERVER['LOCAL_ADDR'] ) ) {
140
  $ip = ! empty( $_SERVER['SERVER_ADDR'] ) ? $_SERVER['SERVER_ADDR'] : $_SERVER['LOCAL_ADDR'];
141
  $ip_arr = array_map( 'intval', explode( '.', $ip ) );
class.jetpack-modules-list-table.php CHANGED
@@ -10,6 +10,12 @@ class Jetpack_Modules_List_Table extends WP_List_Table {
10
 
11
  Jetpack::init();
12
 
 
 
 
 
 
 
13
  $this->items = $this->all_items = Jetpack_Admin::init()->get_modules();
14
  $this->items = $this->filter_displayed_table_items( $this->items );
15
  $this->items = apply_filters( 'jetpack_modules_list_table_items', $this->items );
10
 
11
  Jetpack::init();
12
 
13
+ // In WP 4.2 WP_List_Table will be sanitizing which values are __set()
14
+ global $wp_version;
15
+ if ( version_compare( $wp_version, '4.2-z', '>=' ) ) {
16
+ array_push( $this->compat_fields, 'all_items' );
17
+ }
18
+
19
  $this->items = $this->all_items = Jetpack_Admin::init()->get_modules();
20
  $this->items = $this->filter_displayed_table_items( $this->items );
21
  $this->items = apply_filters( 'jetpack_modules_list_table_items', $this->items );
class.jetpack-options.php CHANGED
@@ -22,6 +22,11 @@ class Jetpack_Options {
22
  'autoupdate_plugins', // (array) An array of plugin ids ( eg. jetpack/jetpack ) that should be autoupdated
23
  'autoupdate_themes', // (array) An array of theme ids ( eg. twentyfourteen ) that should be autoupdated
24
  'autoupdate_core', // (bool) Whether or not to autoupdate core
 
 
 
 
 
25
  );
26
  }
27
 
@@ -44,7 +49,6 @@ class Jetpack_Options {
44
  'gplus_authors', // (array) The Google+ authorship information for connected users.
45
  'last_heartbeat', // (int) The timestamp of the last heartbeat that fired.
46
  'sync_bulk_reindexing', // (bool) If a bulk reindex is currently underway.
47
- 'json_api_full_management', // (bool) Allow full management (eg. Activate, Upgrade plugins) of the site via the JSON API.
48
  );
49
  }
50
 
22
  'autoupdate_plugins', // (array) An array of plugin ids ( eg. jetpack/jetpack ) that should be autoupdated
23
  'autoupdate_themes', // (array) An array of theme ids ( eg. twentyfourteen ) that should be autoupdated
24
  'autoupdate_core', // (bool) Whether or not to autoupdate core
25
+ 'json_api_full_management', // (bool) Allow full management (eg. Activate, Upgrade plugins) of the site via the JSON API.
26
+ 'sync_non_public_post_stati', // (bool) Allow synchronisation of posts and pages with non-public status.
27
+ 'site_icon_url', // (string) url to the full site icon
28
+ 'site_icon_id', // (int) Attachment id of the site icon file
29
+ 'dismissed_manage_banner' // (bool) Dismiss jetpack manage banner allows the user to dismiss the banner permenetly
30
  );
31
  }
32
 
49
  'gplus_authors', // (array) The Google+ authorship information for connected users.
50
  'last_heartbeat', // (int) The timestamp of the last heartbeat that fired.
51
  'sync_bulk_reindexing', // (bool) If a bulk reindex is currently underway.
 
52
  );
53
  }
54
 
class.jetpack-post-images.php CHANGED
@@ -475,6 +475,11 @@ class Jetpack_PostImages {
475
  return $src;
476
  }
477
 
 
 
 
 
 
478
  // If WPCOM hosted image use native transformations
479
  $img_host = parse_url( $src, PHP_URL_HOST );
480
  if ( '.files.wordpress.com' == substr( $img_host, -20 ) ) {
475
  return $src;
476
  }
477
 
478
+ // See if we should bypass WordPress.com SaaS resizing
479
+ if ( has_filter( 'jetpack_images_fit_image_url_override' ) ) {
480
+ return apply_filters( 'jetpack_images_fit_image_url_override', $src, $width, $height );
481
+ }
482
+
483
  // If WPCOM hosted image use native transformations
484
  $img_host = parse_url( $src, PHP_URL_HOST );
485
  if ( '.files.wordpress.com' == substr( $img_host, -20 ) ) {
class.jetpack-sync.php CHANGED
@@ -21,6 +21,7 @@ class Jetpack_Sync {
21
  function __construct() {
22
  // WP Cron action. Only used on upgrade
23
  add_action( 'jetpack_sync_all_registered_options', array( $this, 'sync_all_registered_options' ) );
 
24
  }
25
 
26
  /* Static Methods for Modules */
@@ -467,8 +468,29 @@ class Jetpack_Sync {
467
 
468
  if ( $fid = get_post_thumbnail_id( $id ) ) {
469
  $feature = wp_get_attachment_image_src( $fid, 'large' );
470
- if ( !empty( $feature[0] ) )
471
  $post['extra']['featured_image'] = $feature[0];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  }
473
 
474
  $post['permalink'] = get_permalink( $post_obj->ID );
21
  function __construct() {
22
  // WP Cron action. Only used on upgrade
23
  add_action( 'jetpack_sync_all_registered_options', array( $this, 'sync_all_registered_options' ) );
24
+ add_action( 'jetpack_heartbeat', array( $this, 'sync_all_registered_options' ) );
25
  }
26
 
27
  /* Static Methods for Modules */
468
 
469
  if ( $fid = get_post_thumbnail_id( $id ) ) {
470
  $feature = wp_get_attachment_image_src( $fid, 'large' );
471
+ if ( ! empty( $feature[0] ) ) {
472
  $post['extra']['featured_image'] = $feature[0];
473
+ }
474
+
475
+ $attachment = get_post( $fid );
476
+ if ( ! empty( $attachment ) ) {
477
+ $metadata = wp_get_attachment_metadata( $fid );
478
+
479
+ $post['extra']['post_thumbnail'] = array(
480
+ 'ID' => (int) $fid,
481
+ 'URL' => (string) wp_get_attachment_url( $fid ),
482
+ 'guid' => (string) $attachment->guid,
483
+ 'mime_type' => (string) $attachment->post_mime_type,
484
+ 'width' => (int) isset( $metadata['width'] ) ? $metadata['width'] : 0,
485
+ 'height' => (int) isset( $metadata['height'] ) ? $metadata['height'] : 0,
486
+ );
487
+
488
+ if ( isset( $metadata['duration'] ) ) {
489
+ $post['extra']['post_thumbnail'] = (int) $metadata['duration'];
490
+ }
491
+
492
+ $post['extra']['post_thumbnail'] = (object) apply_filters( 'get_attachment', $post['extra']['post_thumbnail'] );
493
+ }
494
  }
495
 
496
  $post['permalink'] = get_permalink( $post_obj->ID );
class.jetpack-twitter-cards.php CHANGED
@@ -123,6 +123,7 @@ class Jetpack_Twitter_Cards {
123
  $img_count = $extract['count']['image'];
124
 
125
  if ( empty( $img_count ) ) {
 
126
  // No images, use Blavatar as a thumbnail for the summary type.
127
  if ( function_exists('blavatar_domain') ) {
128
  $blavatar_domain = blavatar_domain( site_url() );
@@ -130,7 +131,19 @@ class Jetpack_Twitter_Cards {
130
  $og_tags['twitter:image'] = blavatar_url( $blavatar_domain, 'img', 240 );
131
  }
132
  }
 
 
 
 
 
 
 
 
 
 
 
133
  // Not falling back on Gravatar, because there's no way to know if we end up with an auto-generated one.
 
134
  } elseif ( 1 == $img_count && ( 'image' == $extract['type'] || 'gallery' == $extract['type'] ) ) {
135
  // 1 image = photo
136
  // Test for $extract['type'] to limit to image and gallery, so we don't send a potential fallback image like a Gravatar as a photo post.
@@ -214,4 +227,3 @@ class Jetpack_Twitter_Cards {
214
  }
215
 
216
  Jetpack_Twitter_Cards::init();
217
-
123
  $img_count = $extract['count']['image'];
124
 
125
  if ( empty( $img_count ) ) {
126
+
127
  // No images, use Blavatar as a thumbnail for the summary type.
128
  if ( function_exists('blavatar_domain') ) {
129
  $blavatar_domain = blavatar_domain( site_url() );
131
  $og_tags['twitter:image'] = blavatar_url( $blavatar_domain, 'img', 240 );
132
  }
133
  }
134
+
135
+ // Second fall back, Site Logo
136
+ if ( empty( $og_tags['twitter:image'] ) && ( function_exists( 'jetpack_has_site_logo' ) && jetpack_has_site_logo() ) ) {
137
+ $og_tags['twitter:image'] = jetpack_get_site_logo( 'url' );
138
+ }
139
+
140
+ // Third fall back, Site Icon
141
+ if ( empty( $og_tags['twitter:image'] ) && ( function_exists( 'jetpack_has_site_icon' ) && jetpack_has_site_icon() ) ) {
142
+ $og_tags['twitter:image'] = jetpack_site_icon_url( null, '240' );
143
+ }
144
+
145
  // Not falling back on Gravatar, because there's no way to know if we end up with an auto-generated one.
146
+
147
  } elseif ( 1 == $img_count && ( 'image' == $extract['type'] || 'gallery' == $extract['type'] ) ) {
148
  // 1 image = photo
149
  // Test for $extract['type'] to limit to image and gallery, so we don't send a potential fallback image like a Gravatar as a photo post.
227
  }
228
 
229
  Jetpack_Twitter_Cards::init();
 
class.jetpack.php CHANGED
@@ -330,6 +330,11 @@ class Jetpack {
330
  delete_option( 'hide_gplus' );
331
  delete_metadata( 'post', 0, 'gplus_authorship_disabled', null, true );
332
  }
 
 
 
 
 
333
  }
334
 
335
  /**
@@ -345,8 +350,14 @@ class Jetpack {
345
  * Do things that should run even in the network admin
346
  * here, before we potentially fail out.
347
  */
348
- add_filter( 'jetpack_require_lib_dir', array( $this, 'require_lib_dir' ) );
349
-
 
 
 
 
 
 
350
  /*
351
  * Load things that should only be in Network Admin.
352
  *
@@ -373,9 +384,13 @@ class Jetpack {
373
  'siteurl',
374
  'blogname',
375
  'gmt_offset',
376
- 'timezone_string'
 
 
377
  );
378
 
 
 
379
  if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) {
380
  @ini_set( 'display_errors', false ); // Display errors can cause the XML to be not well formed.
381
 
@@ -408,6 +423,7 @@ class Jetpack {
408
  } else {
409
  if ( Jetpack::is_active() ) {
410
  add_action( 'login_form_jetpack_json_api_authorization', array( &$this, 'login_form_json_api_authorization' ) );
 
411
  }
412
  }
413
 
@@ -445,6 +461,8 @@ class Jetpack {
445
 
446
  add_action( 'plugins_loaded', array( $this, 'extra_oembed_providers' ), 100 );
447
 
 
 
448
  /**
449
  * These actions run checks to load additional files.
450
  * They check for external files or plugins, so they need to run as late as possible.
@@ -621,6 +639,62 @@ class Jetpack {
621
  return JETPACK__PLUGIN_DIR . '_inc/lib';
622
  }
623
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
624
  /**
625
  * Is Jetpack active?
626
  */
@@ -644,6 +718,27 @@ class Jetpack {
644
  return apply_filters( 'jetpack_development_mode', $development_mode );
645
  }
646
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
647
  /**
648
  * Whether Jetpack's version maps to a public release, or a development version.
649
  */
@@ -662,6 +757,24 @@ class Jetpack {
662
  return (bool) Jetpack_Data::get_access_token( $user_id );
663
  }
664
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
665
  /**
666
  * Get the wpcom email of the current|specified connected user.
667
  */
@@ -1819,7 +1932,19 @@ p {
1819
  return Jetpack_Options::get_option( 'log', array() );
1820
  }
1821
 
1822
- /* Admin Pages */
 
 
 
 
 
 
 
 
 
 
 
 
1823
 
1824
  function admin_init() {
1825
  // If the plugin is not connected, display a connect message.
@@ -1848,6 +1973,10 @@ p {
1848
  $args,
1849
  true
1850
  );
 
 
 
 
1851
  }
1852
  /* Toggle this off as it's not ready for prime time just yet.
1853
  if( current_user_can( 'manage_options' ) && self::check_identity_crisis() ) {
@@ -1893,6 +2022,16 @@ p {
1893
  if ( Jetpack::state( 'network_nag' ) )
1894
  add_action( 'network_admin_notices', array( $this, 'network_connect_notice' ) );
1895
  }
 
 
 
 
 
 
 
 
 
 
1896
 
1897
  /**
1898
  * Sometimes a plugin can activate without causing errors, but it will cause errors on the next page load.
@@ -2230,31 +2369,111 @@ p {
2230
 
2231
  $dismiss_and_deactivate_url = wp_nonce_url( Jetpack::admin_url( '?page=jetpack&jetpack-notice=dismiss' ), 'jetpack-deactivate' );
2232
  ?>
2233
- <div id="message" class="updated jetpack-message jp-connect" style="display:block !important;">
2234
- <div id="jp-dismiss" class="jetpack-close-button-container">
2235
- <a class="jetpack-close-button" href="<?php echo esc_url( $dismiss_and_deactivate_url ); ?>" title="<?php _e( 'Dismiss this notice and deactivate Jetpack.', 'jetpack' ); ?>"></a>
2236
- </div>
2237
- <div class="jetpack-wrap-container">
2238
- <div class="jetpack-install-container">
2239
- <?php if ( in_array( Jetpack_Options::get_option( 'activated' ) , array( 1, 2, 3 ) ) ) : ?>
2240
- <p class="submit"><a href="<?php echo $this->build_connect_url() ?>" class="download-jetpack" id="wpcom-connect"><?php _e( 'Connect to WordPress.com', 'jetpack' ); ?></a></p>
2241
- <?php else : ?>
2242
- <p class="submit"><a href="<?php echo Jetpack::admin_url() ?>" class="button-connector" id="wpcom-connect"><?php _e( 'Learn More', 'jetpack' ); ?></a></p>
2243
- <?php endif; ?>
2244
  </div>
2245
- <div class="jetpack-text-container">
2246
- <?php if ( in_array( Jetpack_Options::get_option( 'activated' ) , array( 1, 2, 3 ) ) ) : ?>
2247
- <p><?php _e( '<strong>Your Jetpack is almost ready!</strong>', 'jetpack' ); ?></p>
2248
- <p><?php _e( 'Connect now to enable features like Stats, Likes, and Social Sharing.', 'jetpack' ); ?></p>
2249
- <?php else : ?>
2250
- <p><?php _e( '<strong>Jetpack is installed</strong>', 'jetpack' ) ?></p>
2251
- <p><?php _e( 'It\'s ready to bring awesome, WordPress.com cloud-powered features to your site.', 'jetpack' ) ?></p>
2252
- <?php endif; ?>
 
 
2253
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2254
  </div>
2255
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2256
 
 
 
 
 
 
 
 
2257
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2258
  }
2259
 
2260
  function network_connect_notice() {
@@ -2366,6 +2585,7 @@ p {
2366
  }
2367
  }
2368
 
 
2369
  if ( isset( $_GET['action'] ) ) {
2370
  switch ( $_GET['action'] ) {
2371
  case 'authorize' :
@@ -2599,7 +2819,11 @@ p {
2599
  $active_state = false;
2600
  }
2601
  }
 
 
 
2602
 
 
2603
  switch ( $message_code ) {
2604
  case 'modules_activated' :
2605
  $this->message = sprintf(
@@ -2633,7 +2857,12 @@ p {
2633
 
2634
  $this->message .= Jetpack::jetpack_comment_notice();
2635
  break;
2636
-
 
 
 
 
 
2637
  case 'module_activated' :
2638
  if ( $module = Jetpack::get_module( Jetpack::state( 'module' ) ) ) {
2639
  $this->message = sprintf( __( '<strong>%s Activated!</strong> You can deactivate at any time by clicking the Deactivate link next to each module.', 'jetpack' ), $module['name'] );
@@ -2740,7 +2969,7 @@ p {
2740
 
2741
  $this->privacy_checks = Jetpack::state( 'privacy_checks' );
2742
 
2743
- if ( $this->message || $this->error || $this->privacy_checks ) {
2744
  add_action( 'jetpack_notices', array( $this, 'admin_notices' ) );
2745
  }
2746
 
@@ -2842,6 +3071,11 @@ p {
2842
  </div>
2843
  </div>
2844
  <?php endif;
 
 
 
 
 
2845
  }
2846
 
2847
  /**
@@ -3005,13 +3239,61 @@ p {
3005
  }
3006
 
3007
  function dismiss_jetpack_notice() {
3008
- if ( isset( $_GET['jetpack-notice'] ) && 'dismiss' == $_GET['jetpack-notice'] && check_admin_referer( 'jetpack-deactivate' ) && ! is_plugin_active_for_network( plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ) ) ) {
3009
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
3010
 
3011
- deactivate_plugins( JETPACK__PLUGIN_DIR . 'jetpack.php', false, false );
 
 
 
 
 
 
3012
 
3013
- wp_safe_redirect( admin_url() . 'plugins.php?deactivate=true&plugin_status=all&paged=1&s=' );
3014
- exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3015
  }
3016
  }
3017
 
@@ -3035,7 +3317,6 @@ p {
3035
 
3036
 
3037
 
3038
-
3039
  ?>
3040
  <div class="wrap" id="jetpack-settings">
3041
 
@@ -3074,13 +3355,9 @@ p {
3074
  // If the connection has not been made then show the marketing text.
3075
  if( !$can_reconnect_jpms && !$is_connected ) {
3076
  ?>
3077
- <div id="message" class="updated jetpack-message jp-connect jp-multisite" style="display:block !important">
3078
- <div class="jetpack-wrap-container">
3079
- <div class="jetpack-text-container">
3080
- <h4>
3081
- <p><?php _e( 'To use Jetpack please contact your WordPress administrator to connect it for you.', 'jetpack' ) ?></p>
3082
- </h4>
3083
- </div>
3084
  </div>
3085
  </div> <?php
3086
  }
@@ -3089,19 +3366,14 @@ p {
3089
  <?php if ( ! $is_connected ) :
3090
  $dismiss_and_deactivate_url = wp_nonce_url( Jetpack::admin_url( '?page=jetpack&jetpack-notice=dismiss' ), 'jetpack-deactivate' );
3091
  ?>
3092
- <div id="message" class="updated jetpack-message jp-connect" style="display:block !important;">
3093
- <div id="jp-dismiss" class="jetpack-close-button-container">
3094
- <a class="jetpack-close-button" href="<?php echo esc_url( $dismiss_and_deactivate_url ); ?>"><?php _e( 'Dismiss this notice.', 'jetpack' ); ?></a>
 
 
3095
  </div>
3096
- <div class="jetpack-wrap-container">
3097
- <div class="jetpack-text-container">
3098
- <h4>
3099
- <p><?php _e( 'To enable all of the Jetpack features you&#8217;ll need to connect your website to WordPress.com using the button to the right. Once you&#8217;ve made the connection you&#8217;ll activate all the delightful features below.', 'jetpack' ) ?></p>
3100
- </h4>
3101
- </div>
3102
- <div class="jetpack-install-container">
3103
- <p class="submit"><a href="<?php echo $this->build_connect_url() ?>" class="button-connector" id="wpcom-connect"><?php _e( 'Connect to WordPress.com', 'jetpack' ); ?></a></p>
3104
- </div>
3105
  </div>
3106
  </div>
3107
 
@@ -3116,16 +3388,12 @@ p {
3116
 
3117
  <?php if ( Jetpack::is_active() && !Jetpack::is_development_mode() && ! $is_user_connected ) : ?>
3118
 
3119
- <div id="message" class="updated jetpack-message jp-connect" style="display:block !important;">
3120
- <div class="jetpack-wrap-container">
3121
- <div class="jetpack-text-container">
3122
- <h4>
3123
- <p><?php _e( 'To enable all of the Jetpack features you&#8217;ll need to link your account here to your WordPress.com account using the button to the right.', 'jetpack' ) ?></p>
3124
- </h4>
3125
- </div>
3126
- <div class="jetpack-install-container">
3127
- <p class="submit"><a href="<?php echo $this->build_connect_url() ?>" class="button-connector" id="wpcom-connect"><?php _e( 'Link account with WordPress.com', 'jetpack' ); ?></a></p>
3128
- </div>
3129
  </div>
3130
  </div>
3131
 
@@ -3543,11 +3811,9 @@ p {
3543
  ?>
3544
 
3545
  <div id="message" class="error jetpack-message jp-identity-crisis">
3546
- <div class="jetpack-wrap-container">
3547
- <div class="jetpack-text-container">
3548
- <h3><?php _e( 'Something is being cranky!', 'jetpack' ); ?></h3>
3549
- <p><?php _e( 'Your site is configured to only permit SSL connections to Jetpack, but SSL connections don\'t seem to be functional!', 'jetpack' ); ?></p>
3550
- </div>
3551
  </div>
3552
  </div>
3553
 
@@ -3919,6 +4185,53 @@ p {
3919
  return $methods;
3920
  }
3921
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3922
  function xmlrpc_options( $options ) {
3923
  $options['jetpack_version'] = array(
3924
  'desc' => __( 'Jetpack Plugin Version', 'jetpack' ),
@@ -4455,16 +4768,14 @@ p {
4455
  ?>
4456
 
4457
  <div id="message" class="updated jetpack-message jp-identity-crisis">
4458
- <div class="jetpack-wrap-container">
4459
- <div class="jetpack-text-container">
4460
- <h3><?php _e( 'Something has gotten mixed up!', 'jetpack' ); ?></h3>
4461
- <?php foreach ( $errors as $key => $value ) : ?>
4462
- <p><?php printf( __( 'Your <code>%1$s</code> option is set up as <strong>%2$s</strong>, but your WordPress.com connection lists it as <strong>%3$s</strong>!', 'jetpack' ), $key, (string) get_option( $key ), $value ); ?></p>
4463
- <?php endforeach; ?>
4464
- <p><a href="<?php echo $this->build_reconnect_url() ?>"><?php _e( 'The data listed above is not for my current site. Please disconnect, and then form a new connection to WordPress.com for this site using my current settings.', 'jetpack' ); ?></a></p>
4465
- <p><a href="#"><?php _e( 'Ignore the difference. This is just a staging site for the real site referenced above.', 'jetpack' ); ?></a></p>
4466
- <p><a href="#"><?php _e( 'That used to be my URL for this site before I changed it. Update the WordPress.com Cloud\'s data to match my current settings.', 'jetpack' ); ?></a></p>
4467
- </div>
4468
  </div>
4469
  </div>
4470
 
330
  delete_option( 'hide_gplus' );
331
  delete_metadata( 'post', 0, 'gplus_authorship_disabled', null, true );
332
  }
333
+
334
+ if ( Jetpack::is_active() && Jetpack::maybe_set_version_option() ) {
335
+ do_action( 'jetpack_sync_all_registered_options' );
336
+ }
337
+
338
  }
339
 
340
  /**
350
  * Do things that should run even in the network admin
351
  * here, before we potentially fail out.
352
  */
353
+ add_filter( 'jetpack_require_lib_dir', array( $this, 'require_lib_dir' ) );
354
+ /**
355
+ * Update the main_network_site on .com
356
+ */
357
+ add_filter( 'pre_option_jetpack_main_network_site', array( $this, 'jetpack_main_network_site_option' ) );
358
+ add_action( 'update_option_siteurl', array( $this, 'update_jetpack_main_network_site_option' ) );
359
+ // Update jetpack_is_main_network on .com
360
+ add_filter( 'pre_option_jetpack_is_main_network', array( $this, 'is_main_network_option' ) );
361
  /*
362
  * Load things that should only be in Network Admin.
363
  *
384
  'siteurl',
385
  'blogname',
386
  'gmt_offset',
387
+ 'timezone_string',
388
+ 'jetpack_main_network_site',
389
+ 'jetpack_is_main_network'
390
  );
391
 
392
+ add_action( 'update_option', array( $this, 'log_settings_change' ), 10, 3 );
393
+
394
  if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) {
395
  @ini_set( 'display_errors', false ); // Display errors can cause the XML to be not well formed.
396
 
423
  } else {
424
  if ( Jetpack::is_active() ) {
425
  add_action( 'login_form_jetpack_json_api_authorization', array( &$this, 'login_form_json_api_authorization' ) );
426
+ add_filter( 'xmlrpc_methods', array( $this, 'public_xmlrpc_methods' ) );
427
  }
428
  }
429
 
461
 
462
  add_action( 'plugins_loaded', array( $this, 'extra_oembed_providers' ), 100 );
463
 
464
+ add_action( 'jetpack_notices', array( $this, 'show_development_mode_notice' ) );
465
+
466
  /**
467
  * These actions run checks to load additional files.
468
  * They check for external files or plugins, so they need to run as late as possible.
639
  return JETPACK__PLUGIN_DIR . '_inc/lib';
640
  }
641
 
642
+ /**
643
+ * Return the network_site_url so that .com knows what network this site is a part of.
644
+ * @param bool $option
645
+ * @return string
646
+ */
647
+ function jetpack_main_network_site_option( $option ) {
648
+ return network_site_url();
649
+ }
650
+
651
+ /**
652
+ * Return whether we are dealing with a multi network setup or not.
653
+ * The reason we are type casting this is because we want to avoid the situation where
654
+ * the result is false since when is_main_network_option return false it cases
655
+ * the rest the get_option( 'jetpack_is_multi_network' ); to return the value that is set in the
656
+ * database which could be set to anything as opposed to what this function returns.
657
+ * @param bool $option
658
+ *
659
+ * @return boolean
660
+ */
661
+ public static function is_main_network_option( $option ) {
662
+ // return '1' or ''
663
+ return (string) (bool) Jetpack::is_multi_network();
664
+ }
665
+
666
+ /**
667
+ * Implemented since there is no core is multi network function
668
+ * Right now there is no way to tell if we which network is the dominant network on the system
669
+ *
670
+ * @since 3.3
671
+ * @return boolean
672
+ */
673
+ public static function is_multi_network() {
674
+ global $wpdb;
675
+
676
+ // if we don't have a multi site setup no need to do any more
677
+ if ( ! is_multisite() ) {
678
+ return false;
679
+ }
680
+
681
+ $num_sites = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->site}" );
682
+ if ( $num_sites > 1 ) {
683
+ return true;
684
+ } else {
685
+ return false;
686
+ }
687
+ }
688
+
689
+ /**
690
+ * Trigger an update to the main_network_site when we update the siteurl of a site.
691
+ * @return null
692
+ */
693
+ function update_jetpack_main_network_site_option() {
694
+ do_action( 'add_option_jetpack_main_network_site', 'main_network_site', network_site_url() );
695
+ do_action( 'add_option_jetpack_is_main_network', 'jetpack_is_main_network', (string) (bool) Jetpack::is_multi_network() );
696
+ }
697
+
698
  /**
699
  * Is Jetpack active?
700
  */
718
  return apply_filters( 'jetpack_development_mode', $development_mode );
719
  }
720
 
721
+ /**
722
+ * Get Jetpack development mode notice text and notice class.
723
+ *
724
+ * Mirrors the checks made in Jetpack::is_development_mode
725
+ *
726
+ */
727
+ public static function show_development_mode_notice() {
728
+ if ( Jetpack::is_development_mode() ) {
729
+ if ( defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG ) {
730
+ $notice = __( 'In Development Mode, via the JETPACK_DEV_DEBUG constant being defined in wp-config.php or elsewhere.', 'jetpack' );
731
+ } elseif ( site_url() && false === strpos( site_url(), '.' ) ) {
732
+ $notice = __( 'In Development Mode, via site URL lacking a dot (e.g. http://localhost).', 'jetpack' );
733
+ } else {
734
+ $notice = __( 'In Development Mode, via the jetpack_development_mode filter.', 'jetpack' );
735
+ }
736
+
737
+ $output = '<div class="error"><p>' . $notice . '</p></div>';
738
+ echo $output;
739
+ }
740
+ }
741
+
742
  /**
743
  * Whether Jetpack's version maps to a public release, or a development version.
744
  */
757
  return (bool) Jetpack_Data::get_access_token( $user_id );
758
  }
759
 
760
+ /**
761
+ * Get the wpcom user data of the current|specified connected user.
762
+ */
763
+ public static function get_connected_user_data( $user_id = null ) {
764
+ if ( ! $user_id ) {
765
+ $user_id = get_current_user_id();
766
+ }
767
+ Jetpack::load_xml_rpc_client();
768
+ $xml = new Jetpack_IXR_Client( array(
769
+ 'user_id' => $user_id,
770
+ ) );
771
+ $xml->query( 'wpcom.getUser' );
772
+ if ( ! $xml->isError() ) {
773
+ return $xml->getResponse();
774
+ }
775
+ return false;
776
+ }
777
+
778
  /**
779
  * Get the wpcom email of the current|specified connected user.
780
  */
1932
  return Jetpack_Options::get_option( 'log', array() );
1933
  }
1934
 
1935
+ /**
1936
+ * Log modification of important settings.
1937
+ */
1938
+ public static function log_settings_change( $option, $old_value, $value ) {
1939
+ switch( $option ) {
1940
+ case 'jetpack_sync_non_public_post_stati':
1941
+ case 'jetpack_json_api_full_management':
1942
+ self::log( $option, $value );
1943
+ break;
1944
+ }
1945
+ }
1946
+
1947
+ /* Admin Pages */
1948
 
1949
  function admin_init() {
1950
  // If the plugin is not connected, display a connect message.
1973
  $args,
1974
  true
1975
  );
1976
+ } else {
1977
+ // Show the notice on the Dashboard only for now
1978
+
1979
+ add_action( 'load-index.php', array( $this, 'prepare_manage_jetpack_notice' ) );
1980
  }
1981
  /* Toggle this off as it's not ready for prime time just yet.
1982
  if( current_user_can( 'manage_options' ) && self::check_identity_crisis() ) {
2022
  if ( Jetpack::state( 'network_nag' ) )
2023
  add_action( 'network_admin_notices', array( $this, 'network_connect_notice' ) );
2024
  }
2025
+ /**
2026
+ * Call this function if you want the Big Jetpack Manage Notice to show up.
2027
+ *
2028
+ * @return null
2029
+ */
2030
+ function prepare_manage_jetpack_notice() {
2031
+
2032
+ add_action( 'admin_print_styles', array( $this, 'admin_banner_styles' ) );
2033
+ add_action( 'admin_notices', array( $this, 'admin_jetpack_manage_notice' ) );
2034
+ }
2035
 
2036
  /**
2037
  * Sometimes a plugin can activate without causing errors, but it will cause errors on the next page load.
2369
 
2370
  $dismiss_and_deactivate_url = wp_nonce_url( Jetpack::admin_url( '?page=jetpack&jetpack-notice=dismiss' ), 'jetpack-deactivate' );
2371
  ?>
2372
+ <div id="message" class="updated jetpack-message jp-banner" style="display:block !important;">
2373
+ <a class="jp-banner__dismiss" href="<?php echo esc_url( $dismiss_and_deactivate_url ); ?>" title="<?php esc_attr_e( 'Dismiss this notice and deactivate Jetpack.', 'jetpack' ); ?>"></a>
2374
+ <?php if ( in_array( Jetpack_Options::get_option( 'activated' ) , array( 1, 2, 3 ) ) ) : ?>
2375
+ <div class="jp-banner__content is-connection">
2376
+ <h4><?php _e( 'Your Jetpack is almost ready!', 'jetpack' ); ?></h4>
2377
+ <p><?php _e( 'Connect now to enable features like Stats, Likes, and Social Sharing.', 'jetpack' ); ?></p>
 
 
 
 
 
2378
  </div>
2379
+ <div class="jp-banner__action-container is-connection">
2380
+ <a href="<?php echo $this->build_connect_url() ?>" class="jp-banner__button" id="wpcom-connect"><?php _e( 'Connect to WordPress.com', 'jetpack' ); ?></a>
2381
+ </div>
2382
+ <?php else : ?>
2383
+ <div class="jp-banner__content">
2384
+ <h4><?php _e( 'Jetpack is installed!', 'jetpack' ) ?></h4>
2385
+ <p><?php _e( 'It\'s ready to bring awesome, WordPress.com cloud-powered features to your site.', 'jetpack' ) ?></p>
2386
+ </div>
2387
+ <div class="jp-banner__action-container">
2388
+ <a href="<?php echo Jetpack::admin_url() ?>" class="jp-banner__button" id="wpcom-connect"><?php _e( 'Learn More', 'jetpack' ); ?></a>
2389
  </div>
2390
+ <?php endif; ?>
2391
+ </div>
2392
+
2393
+ <?php
2394
+ }
2395
+
2396
+ /**
2397
+ * This is the first banner
2398
+ * It should be visible only to user that can update the option
2399
+ * Are not connected
2400
+ * @todo make this look nice
2401
+ *
2402
+ * @return null
2403
+ */
2404
+ function admin_jetpack_manage_notice() {
2405
+ // Don't show the connect notice on the jetpack settings page. @todo: must be a better way?
2406
+ if ( false !== strpos( $_SERVER['QUERY_STRING'], 'page=jetpack' ) )
2407
+ return;
2408
+
2409
+ // Only show it if don't have the managment option set.
2410
+ // And not dismissed it already.
2411
+ if ( ! $this->can_display_jetpack_manage_notice() || Jetpack_Options::get_option( 'dismissed_manage_banner' ) ) {
2412
+ return;
2413
+ }
2414
+
2415
+ $opt_out_url = $this->opt_out_jetpack_manage_url();
2416
+ $opt_in_url = $this->opt_in_jetpack_manage_url();
2417
+ /**
2418
+ * I think it would be great to have different wordsing depending on where you are
2419
+ * for example if we show the notice on dashboard and a different one if we show it on Plugins screen
2420
+ * etc..
2421
+ */
2422
+
2423
+ ?>
2424
+ <div id="message" class="updated jetpack-message jp-banner is-opt-in" style="display:block !important;">
2425
+ <a class="jp-banner__dismiss" href="<?php echo esc_url( $opt_out_url ); ?>" title="<?php esc_attr_e( 'Dismiss this notice for now.', 'jetpack' ); ?>"></a>
2426
+ <div class="jp-banner__content">
2427
+ <h4><?php esc_html_e( 'New in Jetpack: Centralized Site Management', 'jetpack' ); ?></h4>
2428
+ <p><?php printf( __( 'Manage multiple sites and keep plugins up-to-date from one dashboard at wordpress.com/plugins. Enabling allows all existing, connected Administrators to modify your site from WordPress.com. <a href="%s" target="_blank">Learn More</a>.', 'jetpack' ), 'http://jetpack.me/support/site-management' ); ?></p>
2429
+ </div>
2430
+ <div class="jp-banner__action-container is-opt-in">
2431
+ <a href="<?php echo esc_url( $opt_in_url ); ?>" class="jp-banner__button" id="wpcom-connect"><?php _e( 'Activate now', 'jetpack' ); ?></a>
2432
  </div>
2433
  </div>
2434
+ <?php
2435
+ }
2436
+
2437
+ /**
2438
+ * Returns the url that the user clicks to remove the notice for the big banner
2439
+ * @return (string)
2440
+ */
2441
+ function opt_out_jetpack_manage_url() {
2442
+ $referer = '&_wp_http_referer=' . add_query_arg( '_wp_http_referer', null );
2443
+ return wp_nonce_url( Jetpack::admin_url( 'jetpack-notice=jetpack-manage-opt-out' . $referer ), 'jetpack_manage_banner_opt_out' );
2444
+ }
2445
+ /**
2446
+ * Returns the url that the user clicks to opt in to Jetpack Manage
2447
+ * @return (string)
2448
+ */
2449
+ function opt_in_jetpack_manage_url() {
2450
+ return wp_nonce_url( Jetpack::admin_url( 'jetpack-notice=jetpack-manage-opt-in' ), 'jetpack_manage_banner_opt_in' );
2451
+ }
2452
 
2453
+ function opt_in_jetpack_manage_notice() {
2454
+ ?>
2455
+ <div class="wrap">
2456
+ <div id="message" class="jetpack-message is-opt-in">
2457
+ <?php echo sprintf( __( '<p><a href="%1$s" title="Opt in to WordPress.com Site Management" >Activate Site Management</a> to manage plugins and multiple sites from our centralized dashboard at wordpress.com/plugins. <a href="%2$s" target="_blank">Learn more</a>.</p><a href="%1$s" class="jp-button">Activate Now</a>', 'jetpack' ), $this->opt_in_jetpack_manage_url(), 'http://jetpack.me/support/site-management' ); ?>
2458
+ </div>
2459
+ </div>
2460
  <?php
2461
+
2462
+ }
2463
+ /**
2464
+ * Determines whether to show the notice of not true = display notice
2465
+ * @return (bool)
2466
+ */
2467
+ function can_display_jetpack_manage_notice() {
2468
+ // never display the notice to users that can't do anything about it anyways
2469
+ if( ! current_user_can( 'jetpack_manage_modules' ) )
2470
+ return false;
2471
+
2472
+ // don't display if we are in development more
2473
+ if( Jetpack::is_development_mode() ) {
2474
+ return false;
2475
+ }
2476
+ return apply_filters( 'can_display_jetpack_manage_notice', ! Jetpack_Options::get_option( 'json_api_full_management' ) || ! self::is_module_active( 'json-api' ) || ! Jetpack_Options::get_option( 'public' ) );
2477
  }
2478
 
2479
  function network_connect_notice() {
2585
  }
2586
  }
2587
 
2588
+
2589
  if ( isset( $_GET['action'] ) ) {
2590
  switch ( $_GET['action'] ) {
2591
  case 'authorize' :
2819
  $active_state = false;
2820
  }
2821
  }
2822
+ if( Jetpack::state( 'optin-manage' ) ) {
2823
+ $activated_jsonapi = $message_code;
2824
+ $message_code = 'jetpack-manage';
2825
 
2826
+ }
2827
  switch ( $message_code ) {
2828
  case 'modules_activated' :
2829
  $this->message = sprintf(
2857
 
2858
  $this->message .= Jetpack::jetpack_comment_notice();
2859
  break;
2860
+ case 'jetpack-manage':
2861
+ $this->message = '<strong>' . sprintf( __( 'You are all set! Your site can now be managed from <a href="%s" target="_blank">wordpress.com/plugins</a>.', 'jetpack' ), 'https://wordpress.com/plugins' ) . '</strong>';
2862
+ if ( $activated_jsonapi ) {
2863
+ $this->message .= '<br /><strong>' . __( 'JSON API has been activated for you!', 'jetpack' ) . '</strong>';
2864
+ }
2865
+ break;
2866
  case 'module_activated' :
2867
  if ( $module = Jetpack::get_module( Jetpack::state( 'module' ) ) ) {
2868
  $this->message = sprintf( __( '<strong>%s Activated!</strong> You can deactivate at any time by clicking the Deactivate link next to each module.', 'jetpack' ), $module['name'] );
2969
 
2970
  $this->privacy_checks = Jetpack::state( 'privacy_checks' );
2971
 
2972
+ if ( $this->message || $this->error || $this->privacy_checks || $this->can_display_jetpack_manage_notice() ) {
2973
  add_action( 'jetpack_notices', array( $this, 'admin_notices' ) );
2974
  }
2975
 
3071
  </div>
3072
  </div>
3073
  <?php endif;
3074
+ // only display the notice if the other stuff is not there
3075
+ if( $this->can_display_jetpack_manage_notice() && ! $this->error && ! $this->message && ! $this->privacy_checks ) {
3076
+ if( isset( $_GET['page'] ) && 'jetpack' != $_GET['page'] )
3077
+ $this->opt_in_jetpack_manage_notice();
3078
+ }
3079
  }
3080
 
3081
  /**
3239
  }
3240
 
3241
  function dismiss_jetpack_notice() {
 
 
3242
 
3243
+ if ( ! isset( $_GET['jetpack-notice'] ) ) {
3244
+ return;
3245
+ }
3246
+
3247
+ switch( $_GET['jetpack-notice'] ) {
3248
+ case 'dismiss':
3249
+ if ( check_admin_referer( 'jetpack-deactivate' ) && ! is_plugin_active_for_network( plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ) ) ) {
3250
 
3251
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
3252
+ deactivate_plugins( JETPACK__PLUGIN_DIR . 'jetpack.php', false, false );
3253
+ wp_safe_redirect( admin_url() . 'plugins.php?deactivate=true&plugin_status=all&paged=1&s=' );
3254
+ }
3255
+ break;
3256
+ case 'jetpack-manage-opt-out':
3257
+
3258
+ if ( check_admin_referer( 'jetpack_manage_banner_opt_out' ) ) {
3259
+ // Don't show the banner again
3260
+
3261
+ Jetpack_Options::update_option( 'dismissed_manage_banner', true );
3262
+ // redirect back to the page that had the notice
3263
+ if ( wp_get_referer() ) {
3264
+ wp_safe_redirect( wp_get_referer() );
3265
+ } else {
3266
+ // Take me to Jetpack
3267
+ wp_safe_redirect( admin_url( 'admin.php?page=jetpack' ) );
3268
+ }
3269
+ }
3270
+ break;
3271
+ case 'jetpack-manage-opt-in':
3272
+ if ( check_admin_referer( 'jetpack_manage_banner_opt_in' ) ) {
3273
+ // This makes sure that we are redirect to jetpack home so that we can see the Success Message.
3274
+
3275
+ $redirection_url = Jetpack::admin_url();
3276
+ remove_action( 'jetpack_pre_activate_module', array( Jetpack_Admin::init(), 'fix_redirect' ) );
3277
+
3278
+ // Don't redirect form the Jetpack Setting Page
3279
+ $referer_parsed = parse_url ( wp_get_referer() );
3280
+ // check that we do have a wp_get_referer and the query paramater is set orderwise go to the Jetpack Home
3281
+ if ( isset( $referer_parsed['query'] ) && false !== strpos( $referer_parsed['query'], 'page=jetpack_modules' ) ) {
3282
+ // Take the user to Jetpack home except when on the setting page
3283
+ $redirection_url = wp_get_referer();
3284
+ add_action( 'jetpack_pre_activate_module', array( Jetpack_Admin::init(), 'fix_redirect' ) );
3285
+ }
3286
+ // Also update the JSON API FULL MANAGEMENT Option
3287
+ Jetpack_Options::update_option( 'json_api_full_management', true );
3288
+ // Special Message when option in.
3289
+ Jetpack::state( 'optin-manage', 'true' );
3290
+ // Activate the Module if not activated already
3291
+ Jetpack::activate_module( 'json-api' );
3292
+ // Redirect properly
3293
+ wp_safe_redirect( $redirection_url );
3294
+
3295
+ }
3296
+ break;
3297
  }
3298
  }
3299
 
3317
 
3318
 
3319
 
 
3320
  ?>
3321
  <div class="wrap" id="jetpack-settings">
3322
 
3355
  // If the connection has not been made then show the marketing text.
3356
  if( !$can_reconnect_jpms && !$is_connected ) {
3357
  ?>
3358
+ <div id="message" class="updated jetpack-message jp-banner jp-multisite" style="display:block !important">
3359
+ <div class="jp-banner__content">
3360
+ <h4><?php _e( 'To use Jetpack please contact your WordPress administrator to connect it for you.', 'jetpack' ) ?></h4>
 
 
 
 
3361
  </div>
3362
  </div> <?php
3363
  }
3366
  <?php if ( ! $is_connected ) :
3367
  $dismiss_and_deactivate_url = wp_nonce_url( Jetpack::admin_url( '?page=jetpack&jetpack-notice=dismiss' ), 'jetpack-deactivate' );
3368
  ?>
3369
+ <div id="message" class="updated jetpack-message jp-banner" style="display:block !important;">
3370
+ <a class="jp-banner__dismiss" href="<?php echo esc_url( $dismiss_and_deactivate_url ); ?>"></a>
3371
+ <div class="jp-banner__content">
3372
+ <h4><?php _e( 'To enable all of the Jetpack features, you&#8217;ll need to connect your website to WordPress.com.', 'jetpack' ) ?></h4>
3373
+ <p><?php _e( 'Once you&#8217;ve made the connection you&#8217;ll activate all the delightful features below.', 'jetpack' ) ?></p>
3374
  </div>
3375
+ <div class="jp-banner__action-container">
3376
+ <a href="<?php echo $this->build_connect_url() ?>" class="jp-banner__button" id="wpcom-connect"><?php _e( 'Connect', 'jetpack' ); ?></a>
 
 
 
 
 
 
 
3377
  </div>
3378
  </div>
3379
 
3388
 
3389
  <?php if ( Jetpack::is_active() && !Jetpack::is_development_mode() && ! $is_user_connected ) : ?>
3390
 
3391
+ <div id="message" class="updated jetpack-message jp-banner" style="display:block !important;">
3392
+ <div class="jp-banner__content">
3393
+ <h4><?php _e( 'To enable all of the Jetpack features you&#8217;ll need to link your account here to your WordPress.com account.', 'jetpack' ) ?></h4>
3394
+ </div>
3395
+ <div class="jp-banner__action-container is-full-width">
3396
+ <a href="<?php echo $this->build_connect_url() ?>" class="jp-banner__button" id="wpcom-connect"><?php _e( 'Link account with WordPress.com', 'jetpack' ); ?></a>
 
 
 
 
3397
  </div>
3398
  </div>
3399
 
3811
  ?>
3812
 
3813
  <div id="message" class="error jetpack-message jp-identity-crisis">
3814
+ <div class="jp-banner__content">
3815
+ <h4><?php _e( 'Something is being cranky!', 'jetpack' ); ?></h4>
3816
+ <p><?php _e( 'Your site is configured to only permit SSL connections to Jetpack, but SSL connections don\'t seem to be functional!', 'jetpack' ); ?></p>
 
 
3817
  </div>
3818
  </div>
3819
 
4185
  return $methods;
4186
  }
4187
 
4188
+ function public_xmlrpc_methods( $methods ) {
4189
+ if ( array_key_exists( 'wp.getOptions', $methods ) ) {
4190
+ $methods['wp.getOptions'] = array( $this, 'jetpack_getOptions' );
4191
+ }
4192
+ return $methods;
4193
+ }
4194
+
4195
+ function jetpack_getOptions( $args ) {
4196
+ global $wp_xmlrpc_server;
4197
+
4198
+ $wp_xmlrpc_server->escape( $args );
4199
+
4200
+ $username = $args[1];
4201
+ $password = $args[2];
4202
+
4203
+ if ( !$user = $wp_xmlrpc_server->login($username, $password) ) {
4204
+ return $wp_xmlrpc_server->error;
4205
+ }
4206
+
4207
+ $options = array();
4208
+ $user_data = $this->get_connected_user_data();
4209
+ if ( is_array( $user_data ) ) {
4210
+ $options['jetpack_user_id'] = array(
4211
+ 'desc' => __( 'The WP.com user ID of the connected user', 'jetpack' ),
4212
+ 'readonly' => true,
4213
+ 'value' => $user_data['ID'],
4214
+ );
4215
+ $options['jetpack_user_login'] = array(
4216
+ 'desc' => __( 'The WP.com username of the connected user', 'jetpack' ),
4217
+ 'readonly' => true,
4218
+ 'value' => $user_data['login'],
4219
+ );
4220
+ $options['jetpack_user_email'] = array(
4221
+ 'desc' => __( 'The WP.com user email of the connected user', 'jetpack' ),
4222
+ 'readonly' => true,
4223
+ 'value' => $user_data['email'],
4224
+ );
4225
+ $options['jetpack_user_site_count'] = array(
4226
+ 'desc' => __( 'The number of sites of the connected WP.com user', 'jetpack' ),
4227
+ 'readonly' => true,
4228
+ 'value' => $user_data['site_count'],
4229
+ );
4230
+ }
4231
+ $wp_xmlrpc_server->blog_options = array_merge( $wp_xmlrpc_server->blog_options, $options );
4232
+ return $wp_xmlrpc_server->wp_getOptions( $args );
4233
+ }
4234
+
4235
  function xmlrpc_options( $options ) {
4236
  $options['jetpack_version'] = array(
4237
  'desc' => __( 'Jetpack Plugin Version', 'jetpack' ),
4768
  ?>
4769
 
4770
  <div id="message" class="updated jetpack-message jp-identity-crisis">
4771
+ <div class="jp-banner__content">
4772
+ <h4><?php _e( 'Something has gotten mixed up!', 'jetpack' ); ?></h4>
4773
+ <?php foreach ( $errors as $key => $value ) : ?>
4774
+ <p><?php printf( __( 'Your <code>%1$s</code> option is set up as <strong>%2$s</strong>, but your WordPress.com connection lists it as <strong>%3$s</strong>!', 'jetpack' ), $key, (string) get_option( $key ), $value ); ?></p>
4775
+ <?php endforeach; ?>
4776
+ <p><a href="<?php echo $this->build_reconnect_url() ?>"><?php _e( 'The data listed above is not for my current site. Please disconnect, and then form a new connection to WordPress.com for this site using my current settings.', 'jetpack' ); ?></a></p>
4777
+ <p><a href="#"><?php _e( 'Ignore the difference. This is just a staging site for the real site referenced above.', 'jetpack' ); ?></a></p>
4778
+ <p><a href="#"><?php _e( 'That used to be my URL for this site before I changed it. Update the WordPress.com Cloud\'s data to match my current settings.', 'jetpack' ); ?></a></p>
 
 
4779
  </div>
4780
  </div>
4781
 
class.json-api-endpoints.php CHANGED
@@ -66,6 +66,9 @@ abstract class WPCOM_JSON_API_Endpoint {
66
  // Is this endpoint still in testing phase? If so, not available to the public.
67
  var $in_testing = false;
68
 
 
 
 
69
  /**
70
  * @var string Version of the API
71
  */
@@ -93,8 +96,8 @@ abstract class WPCOM_JSON_API_Endpoint {
93
 
94
  /**
95
  * @var bool Set to true if the endpoint accepts all cross origin requests
96
- * You probably should not set this flag. If you are thinking of setting it,
97
- * then discuss it with someone:
98
  * http://operationapi.wordpress.com/2014/06/25/patch-allowing-endpoints-to-do-cross-origin-requests/
99
  */
100
  var $allow_cross_origin_request = false;
@@ -102,6 +105,7 @@ abstract class WPCOM_JSON_API_Endpoint {
102
  function __construct( $args ) {
103
  $defaults = array(
104
  'in_testing' => false,
 
105
  'description' => '',
106
  'group' => '',
107
  'method' => 'GET',
@@ -131,6 +135,8 @@ abstract class WPCOM_JSON_API_Endpoint {
131
 
132
  $this->in_testing = $args['in_testing'];
133
 
 
 
134
  $this->description = $args['description'];
135
  $this->group = $args['group'];
136
  $this->stat = $args['stat'];
@@ -517,18 +523,19 @@ abstract class WPCOM_JSON_API_Endpoint {
517
  break;
518
  case 'plugin' :
519
  $docs = array(
520
- 'id' => '(string) The plugin\'s ID',
 
521
  'active' => '(boolean) The plugin status.',
522
  'update' => '(object) The plugin update info.',
523
- 'name' => '(string) The name of the plugin.',
524
  'plugin_url' => '(url) Link to the plugin\'s web site.',
525
- 'version' => '(string) The plugin version number.',
526
  'description' => '(safehtml) Description of what the plugin does and/or notes from the author',
527
- 'author' => '(string) The plugin author\'s name',
528
  'author_url' => '(url) The plugin author web site address',
529
  'network' => '(boolean) Whether the plugin can only be activated network wide.',
530
- 'autoupdate' => '(boolean) Whether the plugin is automatically updated',
531
- 'log' => '(array) An array of log strings telling how the plugin was modified',
532
  );
533
  $return[$key] = (object) $this->cast_and_filter( $value, apply_filters( 'wpcom_json_api_plugin_cast_and_filter', $docs ), false, $for_output );
534
  break;
@@ -548,7 +555,16 @@ abstract class WPCOM_JSON_API_Endpoint {
548
  break;
549
 
550
  default :
551
- trigger_error( "Unknown API casting type {$type['type']}", E_USER_WARNING );
 
 
 
 
 
 
 
 
 
552
  }
553
  }
554
 
@@ -1006,28 +1022,29 @@ EOPHP;
1006
  $$field = str_replace( '&amp;', '&', $$field );
1007
  }
1008
  } else {
1009
- $post = $author;
1010
  if ( isset( $author->post_author ) ) {
 
1011
  if ( 0 == $author->post_author )
1012
  return null;
1013
-
1014
- $author = $author->post_author;
 
 
 
 
 
 
 
 
 
 
1015
  } elseif ( isset( $author->user_id ) && $author->user_id ) {
1016
  $author = $author->user_id;
1017
  } elseif ( isset( $author->user_email ) ) {
1018
  $author = $author->ID;
1019
  }
1020
 
1021
- $is_jetpack = true === apply_filters( 'is_jetpack_site', false, get_current_blog_id() );
1022
-
1023
- if ( $is_jetpack ) {
1024
- $ID = get_post_meta( $post->ID, '_jetpack_post_author_external_id', true );
1025
- $email = get_post_meta( $post->ID, '_jetpack_author_email', true );
1026
- $login = '';
1027
- $name = get_post_meta( $post->ID, '_jetpack_author', true );
1028
- $URL = '';
1029
- $nice = '';
1030
- } else {
1031
  $user = get_user_by( 'id', $author );
1032
  if ( ! $user || is_wp_error( $user ) ) {
1033
  trigger_error( 'Unknown user', E_USER_WARNING );
@@ -1125,14 +1142,14 @@ EOPHP;
1125
  'description' => $media_item->post_content,
1126
  );
1127
 
1128
- if ( in_array( $ext, array( 'jpg', 'jpeg', 'png', 'gif' ) ) ) {
1129
  $metadata = wp_get_attachment_metadata( $media_item->ID );
1130
  $response['height'] = $metadata['height'];
1131
  $response['width'] = $metadata['width'];
1132
  $response['exif'] = $metadata['image_meta'];
1133
  }
1134
 
1135
- if ( in_array( $ext, array( 'mp3', 'm4a', 'wav', 'ogg' ) ) ) {
1136
  $metadata = wp_get_attachment_metadata( $media_item->ID );
1137
  $response['exif'] = $metadata;
1138
  }
@@ -1145,12 +1162,12 @@ EOPHP;
1145
  // add VideoPress info
1146
  if ( function_exists( 'video_get_info_by_blogpostid' ) ) {
1147
  $info = video_get_info_by_blogpostid( $this->api->get_blog_id_for_output(), $media_id );
1148
-
1149
  $response['videopress_guid'] = $info->guid;
1150
  $response['videopress_processing_done'] = true;
1151
  if ( '0000-00-00 00:00:00' == $info->finish_date_gmt ) {
1152
  $response['videopress_processing_done'] = false;
1153
- }
1154
  }
1155
  }
1156
 
@@ -1243,7 +1260,7 @@ EOPHP;
1243
  } else {
1244
  $date_time = date_create( "$date+0000" );
1245
  if ( $date_time ) {
1246
- $timestamp = $date_time->getTimestamp();
1247
  } else {
1248
  $timestamp = 0;
1249
  }
@@ -1444,6 +1461,22 @@ EOPHP;
1444
  return $this->get_link( '/sites/%d/comments/%d', $blog_id, $comment_id, $path );
1445
  }
1446
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1447
  function is_post_type_allowed( $post_type ) {
1448
  // if the post type is empty, that's fine, WordPress will default to post
1449
  if ( empty( $post_type ) )
@@ -1473,6 +1506,103 @@ EOPHP;
1473
  return array_unique( $allowed_types );
1474
  }
1475
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1476
  function handle_media_sideload( $url, $parent_post_id = 0 ) {
1477
  if ( ! function_exists( 'download_url' ) || ! function_exists( 'media_handle_sideload' ) )
1478
  return false;
@@ -1508,6 +1638,49 @@ EOPHP;
1508
  return $id;
1509
  }
1510
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1511
  /**
1512
  * Return endpoint response
1513
  *
66
  // Is this endpoint still in testing phase? If so, not available to the public.
67
  var $in_testing = false;
68
 
69
+ // Is this endpoint still allowed if the site in question is flagged?
70
+ var $allowed_if_flagged = false;
71
+
72
  /**
73
  * @var string Version of the API
74
  */
96
 
97
  /**
98
  * @var bool Set to true if the endpoint accepts all cross origin requests
99
+ * You probably should not set this flag. If you are thinking of setting it,
100
+ * then discuss it with someone:
101
  * http://operationapi.wordpress.com/2014/06/25/patch-allowing-endpoints-to-do-cross-origin-requests/
102
  */
103
  var $allow_cross_origin_request = false;
105
  function __construct( $args ) {
106
  $defaults = array(
107
  'in_testing' => false,
108
+ 'allowed_if_flagged' => false,
109
  'description' => '',
110
  'group' => '',
111
  'method' => 'GET',
135
 
136
  $this->in_testing = $args['in_testing'];
137
 
138
+ $this->allowed_if_flagged = $args['allowed_if_flagged'];
139
+
140
  $this->description = $args['description'];
141
  $this->group = $args['group'];
142
  $this->stat = $args['stat'];
523
  break;
524
  case 'plugin' :
525
  $docs = array(
526
+ 'id' => '(safehtml) The plugin\'s ID',
527
+ 'slug' => '(safehtml) The plugin\'s Slug',
528
  'active' => '(boolean) The plugin status.',
529
  'update' => '(object) The plugin update info.',
530
+ 'name' => '(safehtml) The name of the plugin.',
531
  'plugin_url' => '(url) Link to the plugin\'s web site.',
532
+ 'version' => '(safehtml) The plugin version number.',
533
  'description' => '(safehtml) Description of what the plugin does and/or notes from the author',
534
+ 'author' => '(safehtml) The plugin author\'s name',
535
  'author_url' => '(url) The plugin author web site address',
536
  'network' => '(boolean) Whether the plugin can only be activated network wide.',
537
+ 'autoupdate' => '(boolean) Whether the plugin is auto updated',
538
+ 'log' => '(array:safehtml) An array of update log strings.',
539
  );
540
  $return[$key] = (object) $this->cast_and_filter( $value, apply_filters( 'wpcom_json_api_plugin_cast_and_filter', $docs ), false, $for_output );
541
  break;
555
  break;
556
 
557
  default :
558
+ $method_name = $type['type'] . '_docs';
559
+ if ( method_exists( WPCOM_JSON_API_Jetpack_Overrides, $method_name ) ) {
560
+ $docs = WPCOM_JSON_API_Jetpack_Overrides::$method_name();
561
+ }
562
+
563
+ if ( ! empty( $docs ) ) {
564
+ $return[$key] = (object) $this->cast_and_filter( $value, apply_filters( 'wpcom_json_api_plugin_cast_and_filter', $docs ), false, $for_output );
565
+ } else {
566
+ trigger_error( "Unknown API casting type {$type['type']}", E_USER_WARNING );
567
+ }
568
  }
569
  }
570
 
1022
  $$field = str_replace( '&amp;', '&', $$field );
1023
  }
1024
  } else {
 
1025
  if ( isset( $author->post_author ) ) {
1026
+ // then $author is a Post Object.
1027
  if ( 0 == $author->post_author )
1028
  return null;
1029
+ $is_jetpack = true === apply_filters( 'is_jetpack_site', false, get_current_blog_id() );
1030
+ $post_id = $author->ID;
1031
+ if ( $is_jetpack ) {
1032
+ $ID = get_post_meta( $post_id, '_jetpack_post_author_external_id', true );
1033
+ $email = get_post_meta( $post_id, '_jetpack_author_email', true );
1034
+ $login = '';
1035
+ $name = get_post_meta( $post_id, '_jetpack_author', true );
1036
+ $URL = '';
1037
+ $nice = '';
1038
+ } else {
1039
+ $author = $author->post_author;
1040
+ }
1041
  } elseif ( isset( $author->user_id ) && $author->user_id ) {
1042
  $author = $author->user_id;
1043
  } elseif ( isset( $author->user_email ) ) {
1044
  $author = $author->ID;
1045
  }
1046
 
1047
+ if ( ! isset( $ID ) ) {
 
 
 
 
 
 
 
 
 
1048
  $user = get_user_by( 'id', $author );
1049
  if ( ! $user || is_wp_error( $user ) ) {
1050
  trigger_error( 'Unknown user', E_USER_WARNING );
1142
  'description' => $media_item->post_content,
1143
  );
1144
 
1145
+ if ( in_array( $ext, array( 'jpg', 'jpeg', 'png', 'gif' ) ) ) {
1146
  $metadata = wp_get_attachment_metadata( $media_item->ID );
1147
  $response['height'] = $metadata['height'];
1148
  $response['width'] = $metadata['width'];
1149
  $response['exif'] = $metadata['image_meta'];
1150
  }
1151
 
1152
+ if ( in_array( $ext, array( 'mp3', 'm4a', 'wav', 'ogg' ) ) ) {
1153
  $metadata = wp_get_attachment_metadata( $media_item->ID );
1154
  $response['exif'] = $metadata;
1155
  }
1162
  // add VideoPress info
1163
  if ( function_exists( 'video_get_info_by_blogpostid' ) ) {
1164
  $info = video_get_info_by_blogpostid( $this->api->get_blog_id_for_output(), $media_id );
1165
+
1166
  $response['videopress_guid'] = $info->guid;
1167
  $response['videopress_processing_done'] = true;
1168
  if ( '0000-00-00 00:00:00' == $info->finish_date_gmt ) {
1169
  $response['videopress_processing_done'] = false;
1170
+ }
1171
  }
1172
  }
1173
 
1260
  } else {
1261
  $date_time = date_create( "$date+0000" );
1262
  if ( $date_time ) {
1263
+ $timestamp = date_format( $date_time, 'U' );
1264
  } else {
1265
  $timestamp = 0;
1266
  }
1461
  return $this->get_link( '/sites/%d/comments/%d', $blog_id, $comment_id, $path );
1462
  }
1463
 
1464
+ function get_publicize_connection_link( $blog_id, $publicize_connection_id, $path = '' ) {
1465
+ return $this->get_link( '.1/sites/%d/publicize-connections/%d', $blog_id, $publicize_connection_id, $path );
1466
+ }
1467
+
1468
+ function get_publicize_connections_link( $keyring_token_id, $path = '' ) {
1469
+ return $this->get_link( '.1/me/publicize-connections/?keyring_token_ID=%d', $keyring_token_id, $path );
1470
+ }
1471
+
1472
+ function get_keyring_token_link( $keyring_token_id, $path = '' ) {
1473
+ return $this->get_link( '.1/me/keyring-tokens/%d', $keyring_token_id, $path );
1474
+ }
1475
+
1476
+ function get_external_service_link( $external_service, $path = '' ) {
1477
+ return $this->get_link( '.1/meta/external-services/%s', $external_service, $path );
1478
+ }
1479
+
1480
  function is_post_type_allowed( $post_type ) {
1481
  // if the post type is empty, that's fine, WordPress will default to post
1482
  if ( empty( $post_type ) )
1506
  return array_unique( $allowed_types );
1507
  }
1508
 
1509
+ function handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs = array(), $force_parent_id = false ) {
1510
+
1511
+ add_filter( 'upload_mimes', array( $this, 'allow_video_uploads' ) );
1512
+
1513
+ $media_ids = $errors = array();
1514
+ $user_can_upload_files = current_user_can( 'upload_files' );
1515
+ $media_attrs = array_values( $media_attrs ); // reset the keys
1516
+ $i = 0;
1517
+
1518
+ if ( ! empty( $media_files ) ) {
1519
+ $this->api->trap_wp_die( 'upload_error' );
1520
+ foreach ( $media_files as $media_item ) {
1521
+ $_FILES['.api.media.item.'] = $media_item;
1522
+ if ( ! $user_can_upload_files ) {
1523
+ $media_id = new WP_Error( 'unauthorized', 'User cannot upload media.', 403 );
1524
+ } else {
1525
+ if ( $force_parent_id ) {
1526
+ $parent_id = absint( $force_parent_id );
1527
+ } elseif ( ! empty( $media_attrs[$i] ) && ! empty( $media_attrs[$i]['parent_id'] ) ) {
1528
+ $parent_id = absint( $media_attrs[$i]['parent_id'] );
1529
+ } else {
1530
+ $parent_id = 0;
1531
+ }
1532
+ $media_id = media_handle_upload( '.api.media.item.', $parent_id );
1533
+ }
1534
+ if ( is_wp_error( $media_id ) ) {
1535
+ $errors[$i]['file'] = $media_item['name'];
1536
+ $errors[$i]['error'] = $media_id->get_error_code();
1537
+ $errors[$i]['message'] = $media_id->get_error_message();
1538
+ } else {
1539
+ $media_ids[$i] = $media_id;
1540
+ }
1541
+
1542
+ $i++;
1543
+ }
1544
+ $this->api->trap_wp_die( null );
1545
+ unset( $_FILES['.api.media.item.'] );
1546
+ }
1547
+
1548
+ if ( ! empty( $media_urls ) ) {
1549
+ foreach ( $media_urls as $url ) {
1550
+ if ( ! $user_can_upload_files ) {
1551
+ $media_id = new WP_Error( 'unauthorized', 'User cannot upload media.', 403 );
1552
+ } else {
1553
+ if ( $force_parent_id ) {
1554
+ $parent_id = absint( $force_parent_id );
1555
+ } else if ( ! empty( $media_attrs[$i] ) && ! empty( $media_attrs[$i]['parent_id'] ) ) {
1556
+ $parent_id = absint( $media_attrs[$i]['parent_id'] );
1557
+ } else {
1558
+ $parent_id = 0;
1559
+ }
1560
+ $media_id = $this->handle_media_sideload( $url, $parent_id );
1561
+ }
1562
+ if ( is_wp_error( $media_id ) ) {
1563
+ $errors[$i] = array(
1564
+ 'file' => $url,
1565
+ 'error' => $media_id->get_error_code(),
1566
+ 'message' => $media_id->get_error_message(),
1567
+ );
1568
+ } elseif ( ! empty( $media_id ) ) {
1569
+ $media_ids[$i] = $media_id;
1570
+ }
1571
+
1572
+ $i++;
1573
+ }
1574
+ }
1575
+
1576
+ if ( ! empty( $media_attrs ) ) {
1577
+ foreach ( $media_ids as $index => $media_id ) {
1578
+ if ( empty( $media_attrs[$index] ) )
1579
+ continue;
1580
+
1581
+ $attrs = $media_attrs[$index];
1582
+ $insert = array();
1583
+
1584
+ if ( ! empty( $attrs['title'] ) ) {
1585
+ $insert['post_title'] = $attrs['title'];
1586
+ }
1587
+
1588
+ if ( ! empty( $attrs['caption'] ) )
1589
+ $insert['post_excerpt'] = $attrs['caption'];
1590
+
1591
+ if ( ! empty( $attrs['description'] ) )
1592
+ $insert['post_content'] = $attrs['description'];
1593
+
1594
+ if ( empty( $insert ) )
1595
+ continue;
1596
+
1597
+ $insert['ID'] = $media_id;
1598
+ wp_update_post( (object) $insert );
1599
+ }
1600
+ }
1601
+
1602
+ return array( 'media_ids' => $media_ids, 'errors' => $errors );
1603
+
1604
+ }
1605
+
1606
  function handle_media_sideload( $url, $parent_post_id = 0 ) {
1607
  if ( ! function_exists( 'download_url' ) || ! function_exists( 'media_handle_sideload' ) )
1608
  return false;
1638
  return $id;
1639
  }
1640
 
1641
+ function allow_video_uploads( $mimes ) {
1642
+ // if we are on Jetpack, bail - Videos are already allowed
1643
+ if ( ! defined( 'IS_WPCOM' ) || !IS_WPCOM ) {
1644
+ return $mimes;
1645
+ }
1646
+
1647
+ // extra check that this filter is only ever applied during REST API requests
1648
+ if ( ! defined( 'REST_API_REQUEST' ) || ! REST_API_REQUEST ) {
1649
+ return $mimes;
1650
+ }
1651
+
1652
+ // bail early if they already have the upgrade..
1653
+ if ( get_option( 'video_upgrade' ) == '1' ) {
1654
+ return $mimes;
1655
+ }
1656
+
1657
+ // lets whitelist to only specific clients right now
1658
+ $clients_allowed_video_uploads = array();
1659
+ $clients_allowed_video_uploads = apply_filters( 'rest_api_clients_allowed_video_uploads', $clients_allowed_video_uploads );
1660
+ if ( !in_array( $this->api->token_details['client_id'], $clients_allowed_video_uploads ) ) {
1661
+ return $mimes;
1662
+ }
1663
+
1664
+ $mime_list = wp_get_mime_types();
1665
+
1666
+ $video_exts = explode( ' ', get_site_option( 'video_upload_filetypes', false, false ) );
1667
+ $video_exts = apply_filters( 'video_upload_filetypes', $video_exts );
1668
+ $video_mimes = array();
1669
+
1670
+ if ( !empty( $video_exts ) ) {
1671
+ foreach ( $video_exts as $ext ) {
1672
+ foreach ( $mime_list as $ext_pattern => $mime ) {
1673
+ if ( $ext != '' && strpos( $ext_pattern, $ext ) !== false )
1674
+ $video_mimes[$ext_pattern] = $mime;
1675
+ }
1676
+ }
1677
+
1678
+ $mimes = array_merge( $mimes, $video_mimes );
1679
+ }
1680
+
1681
+ return $mimes;
1682
+ }
1683
+
1684
  /**
1685
  * Return endpoint response
1686
  *
class.json-api.php CHANGED
@@ -1,9 +1,6 @@
1
  <?php
2
- defined( 'WPCOM_JSON_API__DEBUG' ) or define( 'WPCOM_JSON_API__DEBUG', false );
3
- if( defined( 'WPCOM_JSON_API__DEBUG' ) && WPCOM_JSON_API__DEBUG )
4
- require_once ABSPATH . 'wp-content/lib/statsd-client.php';
5
-
6
 
 
7
 
8
  class WPCOM_JSON_API {
9
  static $self = null;
@@ -26,6 +23,8 @@ class WPCOM_JSON_API {
26
  var $exit = true;
27
  var $public_api_scheme = 'https';
28
 
 
 
29
  var $trapped_error = null;
30
  var $did_output = false;
31
 
@@ -135,6 +134,11 @@ class WPCOM_JSON_API {
135
  add_filter( 'comment_edit_pre', array( $this, 'comment_edit_pre' ) );
136
 
137
  $initialization = $this->initialize();
 
 
 
 
 
138
  if ( is_wp_error( $initialization ) ) {
139
  $this->output_error( $initialization );
140
  return;
@@ -152,11 +156,6 @@ class WPCOM_JSON_API {
152
  $is_help = preg_match( '#/help/?$#i', $this->path );
153
  $matching_endpoints = array();
154
 
155
- if ( 'OPTIONS' == $this->method ) {
156
- do_action( 'wpcom_json_api_options' );
157
- exit;
158
- }
159
-
160
  if ( $is_help ) {
161
  $origin = get_http_origin();
162
 
@@ -279,29 +278,15 @@ class WPCOM_JSON_API {
279
  return $this->output_error( $response );
280
  }
281
 
282
- return $this->output( 200, $response );
 
 
 
283
  }
284
 
285
  function process_request( WPCOM_JSON_API_Endpoint $endpoint, $path_pieces ) {
286
  $this->endpoint = $endpoint;
287
-
288
- // Process API request and time it
289
- $api_timer = microtime( true );
290
- $response = call_user_func_array( array( $endpoint, 'callback' ), $path_pieces );
291
- $api_timer = 1000 * ( microtime( true ) - $api_timer );
292
- if( defined( 'WPCOM_JSON_API__DEBUG' ) && WPCOM_JSON_API__DEBUG ) {
293
- // Don't track API timings per node / DC for now, maybe in the future
294
- $statsd = new StatsD();
295
- $statsd_prefix = 'com.wordpress.web.ALL.ALL.rest_api.method';
296
- $statsd_name = str_replace( ':', '.', $endpoint->stat );
297
-
298
- if ( ( !$response && !is_array( $response ) ) || is_wp_error( $response ) ) {
299
- $statsd->timing( "{$statsd_prefix}.error.{$statsd_name}", $api_timer );
300
- } else {
301
- $statsd->timing( "{$statsd_prefix}.ok.{$statsd_name}", $api_timer );
302
- }
303
- }
304
- return $response;
305
  }
306
 
307
  function output_early( $status_code, $response = null, $content_type = 'application/json' ) {
@@ -315,6 +300,10 @@ class WPCOM_JSON_API {
315
  $this->finish_request();
316
  }
317
 
 
 
 
 
318
  function output( $status_code, $response = null, $content_type = 'application/json' ) {
319
  // In case output() was called before the callback returned
320
  if ( $this->did_output ) {
1
  <?php
 
 
 
 
2
 
3
+ defined( 'WPCOM_JSON_API__DEBUG' ) or define( 'WPCOM_JSON_API__DEBUG', false );
4
 
5
  class WPCOM_JSON_API {
6
  static $self = null;
23
  var $exit = true;
24
  var $public_api_scheme = 'https';
25
 
26
+ var $output_status_code = 200;
27
+
28
  var $trapped_error = null;
29
  var $did_output = false;
30
 
134
  add_filter( 'comment_edit_pre', array( $this, 'comment_edit_pre' ) );
135
 
136
  $initialization = $this->initialize();
137
+ if ( 'OPTIONS' == $this->method ) {
138
+ do_action( 'wpcom_json_api_options' );
139
+ return $this->output( 200, '', 'plain/text' );
140
+ }
141
+
142
  if ( is_wp_error( $initialization ) ) {
143
  $this->output_error( $initialization );
144
  return;
156
  $is_help = preg_match( '#/help/?$#i', $this->path );
157
  $matching_endpoints = array();
158
 
 
 
 
 
 
159
  if ( $is_help ) {
160
  $origin = get_http_origin();
161
 
278
  return $this->output_error( $response );
279
  }
280
 
281
+ $output_status_code = $this->output_status_code;
282
+ $this->set_output_status_code();
283
+
284
+ return $this->output( $output_status_code, $response );
285
  }
286
 
287
  function process_request( WPCOM_JSON_API_Endpoint $endpoint, $path_pieces ) {
288
  $this->endpoint = $endpoint;
289
+ return call_user_func_array( array( $endpoint, 'callback' ), $path_pieces );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  }
291
 
292
  function output_early( $status_code, $response = null, $content_type = 'application/json' ) {
300
  $this->finish_request();
301
  }
302
 
303
+ function set_output_status_code( $code = 200 ) {
304
+ $this->output_status_code = $code;
305
+ }
306
+
307
  function output( $status_code, $response = null, $content_type = 'application/json' ) {
308
  // In case output() was called before the callback returned
309
  if ( $this->did_output ) {
class.media-extractor.php CHANGED
@@ -24,6 +24,7 @@ class Jetpack_Media_Meta_Extractor {
24
  'hulu',
25
  'ted',
26
  'wpvideo',
 
27
  );
28
 
29
  /**
24
  'hulu',
25
  'ted',
26
  'wpvideo',
27
+ 'audio',
28
  );
29
 
30
  /**
class.media-summary.php CHANGED
@@ -152,17 +152,15 @@ class Jetpack_Media_Summary {
152
 
153
  // If we don't have any prioritized embed...
154
  if ( 'standard' == $return['type'] ) {
155
- if ( !empty( $extract['has']['gallery'] ) || ! empty( $extract['shortcode']['gallery']['count'] ) ) {
156
  //... Then we prioritize galleries first (multiple images returned)
157
  $return['type'] = 'gallery';
158
- if ( isset( $extract['image'] ) || ! empty( $extract['image'] ) ) {
159
  $return['images'] = $extract['image'];
160
- foreach ( $return['images'] as $image ) {
161
- $return['secure']['images'][] = array( 'url' => self::ssl_img( $image['url'] ) );
162
- $return['count']['image']++;
163
- }
164
  }
165
- } else if ( !empty( $extract['has']['image'] ) ) {
166
  // ... Or we try and select a single image that would make sense
167
  $content = wpautop( strip_tags( $post->post_content ) );
168
  $paragraphs = explode( '</p>', $content );
152
 
153
  // If we don't have any prioritized embed...
154
  if ( 'standard' == $return['type'] ) {
155
+ if ( ( ! empty( $extract['has']['gallery'] ) || ! empty( $extract['shortcode']['gallery']['count'] ) ) && ! empty( $extract['image'] ) ) {
156
  //... Then we prioritize galleries first (multiple images returned)
157
  $return['type'] = 'gallery';
 
158
  $return['images'] = $extract['image'];
159
+ foreach ( $return['images'] as $image ) {
160
+ $return['secure']['images'][] = array( 'url' => self::ssl_img( $image['url'] ) );
161
+ $return['count']['image']++;
 
162
  }
163
+ } else if ( ! empty( $extract['has']['image'] ) ) {
164
  // ... Or we try and select a single image that would make sense
165
  $content = wpautop( strip_tags( $post->post_content ) );
166
  $paragraphs = explode( '</p>', $content );
class.photon.php CHANGED
@@ -53,7 +53,7 @@ class Jetpack_Photon {
53
 
54
  // Images in post content and galleries
55
  add_filter( 'the_content', array( __CLASS__, 'filter_the_content' ), 999999 );
56
- add_filter( 'get_post_gallery', array( __CLASS__, 'filter_the_content' ), 999999 );
57
 
58
  // Core image retrieval
59
  add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 10, 3 );
@@ -319,6 +319,29 @@ class Jetpack_Photon {
319
  return $content;
320
  }
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  /**
323
  ** CORE IMAGE RETRIEVAL
324
  **/
53
 
54
  // Images in post content and galleries
55
  add_filter( 'the_content', array( __CLASS__, 'filter_the_content' ), 999999 );
56
+ add_filter( 'get_post_galleries', array( __CLASS__, 'filter_the_galleries' ), 999999 );
57
 
58
  // Core image retrieval
59
  add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 10, 3 );
319
  return $content;
320
  }
321
 
322
+ public static function filter_the_galleries( $galleries ) {
323
+ if ( empty( $galleries ) || ! is_array( $galleries ) ) {
324
+ return $galleries;
325
+ }
326
+
327
+ // Pass by reference, so we can modify them in place.
328
+ foreach ( $galleries as &$this_gallery ) {
329
+ if ( is_string( $this_gallery ) ) {
330
+ $this_gallery = self::filter_the_content( $this_gallery );
331
+ // LEAVING COMMENTED OUT as for the moment it doesn't seem
332
+ // necessary and I'm not sure how it would propagate through.
333
+ // } elseif ( is_array( $this_gallery )
334
+ // && ! empty( $this_gallery['src'] )
335
+ // && ! empty( $this_gallery['type'] )
336
+ // && in_array( $this_gallery['type'], array( 'rectangle', 'square', 'circle' ) ) ) {
337
+ // $this_gallery['src'] = array_map( 'jetpack_photon_url', $this_gallery['src'] );
338
+ }
339
+ }
340
+ unset( $this_gallery ); // break the reference.
341
+
342
+ return $galleries;
343
+ }
344
+
345
  /**
346
  ** CORE IMAGE RETRIEVAL
347
  **/
css/jetpack-admin-rtl.css CHANGED
@@ -26,7 +26,6 @@ h6 {
26
 
27
  a {
28
  color: #0d72b2;
29
- -webkit-transition: color .2s;
30
  transition: color .2s;
31
  text-decoration: none;
32
  }
@@ -168,7 +167,6 @@ img {
168
  }
169
  .button,
170
  .download-jetpack {
171
- -webkit-transition: all .1s ease-in-out;
172
  transition: all .1s ease-in-out;
173
  }
174
 
@@ -178,7 +176,7 @@ img {
178
  padding: 0.76923em 1.46154em;
179
  color: #efefef;
180
  font: 800 0.9285714286em/1 'Open Sans', Helvetica, sans-serif;
181
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
182
  background: #6f7476;
183
  border-radius: 3px;
184
  }
@@ -216,7 +214,7 @@ img {
216
  position: relative;
217
  padding: 0.64286em 0.85714em 0.53571em;
218
  color: #fff;
219
- font: 400 2em/1 "proxima-nova", 'Open Sans', Helvetica, sans-serif;
220
  background: #518d2a;
221
  z-index: 3;
222
  border-radius: 6px;
@@ -291,7 +289,7 @@ img {
291
  padding: 0.71429em 1.5em;
292
  color: #efefef;
293
  font: 800 0.8em/1 'Open Sans', Helvetica, sans-serif;
294
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
295
  background: #6f7476;
296
  outline: none;
297
  border-radius: 3px;
@@ -324,7 +322,7 @@ img {
324
  @media screen and (-webkit-min-device-pixel-ratio: 0) {
325
  @font-face {
326
  font-family: "jetpack";
327
- src: url("fonts/jetpack.svg#jetpack") format("svg");
328
  }
329
  }
330
  .nav-horizontal a {
@@ -550,7 +548,6 @@ ul#adminmenu a.toplevel_page_jetpack:after {
550
  text-align: center;
551
  z-index: 1;
552
  background-color: #81a844;
553
- background-image: -webkit-linear-gradient(top, #81a844, #8eb74e);
554
  background-image: linear-gradient(top, #81a844, #8eb74e);
555
  }
556
  .masthead.hasbutton .flyer {
@@ -575,7 +572,7 @@ ul#adminmenu a.toplevel_page_jetpack:after {
575
  color: #fff;
576
  font: 300 2.57143em/1.4em "proxima-nova", "Open Sans", Helvetica, Arial, sans-serif;
577
  position: relative;
578
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.12);
579
  z-index: 3;
580
  }
581
  .masthead h1 + .flyby {
@@ -656,7 +653,7 @@ ul#adminmenu a.toplevel_page_jetpack:after {
656
  max-width: 460px;
657
  color: #5d6d74;
658
  font: 400 1.57143em/1.4em "proxima-nova", "Open Sans", Helvetica, Arial, sans-serif;
659
- text-shadow: 0 1px 1px #fff;
660
  }
661
  @media (max-width: 900px) {
662
  .subhead h2 {
@@ -709,8 +706,6 @@ ul#adminmenu a.toplevel_page_jetpack:after {
709
  text-align: center;
710
  z-index: 1;
711
  background-color: #81a844;
712
- background-image: -webkit-gradient(linear, right top, right bottom, from(#81a844), to(#89b348));
713
- background-image: -webkit-linear-gradient(top, #81a844, #89b348);
714
  background-image: linear-gradient(top, #81a844, #89b348);
715
  }
716
  .clouds-sm:after {
@@ -764,7 +759,7 @@ ul#adminmenu a.toplevel_page_jetpack:after {
764
  color: #5d6d74;
765
  font: 300 2.57143em/1.4em "proxima-nova", "Open Sans", Helvetica, Arial, sans-serif;
766
  text-align: center;
767
- text-shadow: 0 1px 1px #fff;
768
  }
769
  @media (max-width: 900px) {
770
  .featured h2,
@@ -789,7 +784,6 @@ ul#adminmenu a.toplevel_page_jetpack:after {
789
  float: right;
790
  margin: 0 5px 10px;
791
  width: 310px;
792
- -webkit-transition: all .2s ease-in-out;
793
  transition: all .2s ease-in-out;
794
  }
795
  @media (max-width: 1147px) {
@@ -797,7 +791,6 @@ ul#adminmenu a.toplevel_page_jetpack:after {
797
  .module {
798
  margin: .75% 1.5% .75% 0;
799
  width: 32.333333%;
800
- -webkit-transition: none;
801
  transition: none;
802
  }
803
  .feature:nth-child(3n + 1),
@@ -837,7 +830,6 @@ ul#adminmenu a.toplevel_page_jetpack:after {
837
  z-index: -1;
838
  -webkit-transform: translateZ(0);
839
  transform: translateZ(0);
840
- -webkit-transition: all .2s ease-in-out;
841
  transition: all .2s ease-in-out;
842
  }
843
  .feature:hover {
@@ -1008,7 +1000,6 @@ ul#adminmenu a.toplevel_page_jetpack:after {
1008
  text-indent: -9999px;
1009
  pointer-events: none;
1010
  border-radius: 3px;
1011
- -webkit-transition: all .2s ease-in-out;
1012
  transition: all .2s ease-in-out;
1013
  }
1014
  #jetpack-search + label:after {
@@ -1032,14 +1023,14 @@ ul#adminmenu a.toplevel_page_jetpack:after {
1032
  padding: 0.76923em 1.46154em;
1033
  color: #aaa;
1034
  font: 600 0.92857em/1 "Open Sans", Helvetica, Arial, sans-serif;
1035
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
1036
  background: #eee;
1037
  border-radius: 3px;
1038
  background-clip: padding-box;
1039
  }
1040
  .jp-filter a.selected, .jp-filter a:hover, .jp-filter a:focus {
1041
  color: #efefef;
1042
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
1043
  background: #6f7476;
1044
  }
1045
  @media (max-width: 530px) {
@@ -1056,7 +1047,6 @@ ul#adminmenu a.toplevel_page_jetpack:after {
1056
  border: 1px solid #dae0e2;
1057
  background: #fff;
1058
  box-shadow: 0 0 0 rgba(0, 0, 0, 0.03);
1059
- -webkit-transition: opacity 2s ease-in;
1060
  transition: opacity 2s ease-in;
1061
  }
1062
  .module:hover {
@@ -1087,11 +1077,11 @@ ul#adminmenu a.toplevel_page_jetpack:after {
1087
  }
1088
  .module.active {
1089
  border-color: #2ea2cc;
1090
- box-shadow: inset 4px 0