Jetpack by WordPress.com - Version 2.2.8

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 2.2.8
Comparing to
See all releases

Code changes from version 2.0.7 to 2.2.8

_inc/gallery-settings.js ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Jetpack Gallery Settings
3
+ */
4
+ (function($) {
5
+ var media = wp.media;
6
+
7
+ // Wrap the render() function to append controls.
8
+ media.view.Settings.Gallery = media.view.Settings.Gallery.extend({
9
+ render: function() {
10
+ var $el = this.$el;
11
+
12
+ media.view.Settings.prototype.render.apply( this, arguments );
13
+
14
+ // Append the type template and update the settings.
15
+ $el.append( media.template( 'jetpack-gallery-settings' ) );
16
+ media.gallery.defaults.type = 'default'; // lil hack that lets media know there's a type attribute.
17
+ this.update.apply( this, ['type'] );
18
+
19
+ // Hide the Columns setting for all types except Default
20
+ $el.find( 'select[name=type]' ).on( 'change', function () {
21
+ var columnSetting = $el.find( 'select[name=columns]' ).closest( 'label.setting' );
22
+
23
+ if ( 'default' == $( this ).val() )
24
+ columnSetting.show();
25
+ else
26
+ columnSetting.hide();
27
+ } ).change();
28
+
29
+ return this;
30
+ }
31
+ });
32
+ })(jQuery);
_inc/images/module-icons-sprite-2x.png CHANGED
Binary file
_inc/images/module-icons-sprite.png CHANGED
Binary file
screenshot-6.png → _inc/images/screenshots/carousel.png RENAMED
File without changes
_inc/images/screenshots/likes.png ADDED
Binary file
_inc/images/screenshots/tiled-gallery.png ADDED
Binary file
_inc/jetpack-retina.css CHANGED
@@ -78,7 +78,7 @@
78
  /* Pointer dismiss button */
79
  .wp-pointer-buttons a.close::before {
80
  background-image: url('images/xit-2x.gif');
81
- background-size: 20px 10px;
82
  }
83
 
84
  /* Pointer icon */
@@ -101,7 +101,7 @@
101
  body.admin-color-classic #screen-meta-links a.show-settings {
102
  background-image: url('images/arrows-vs-2x.png') !important;
103
  }
104
-
105
  /* Collapse button divs */
106
  #collapse-button div {
107
  background-image: url('images/arrows-2x.png') !important;
@@ -236,7 +236,7 @@
236
  background-image: url("images/down_arrow-2x.gif") !important;
237
  background-size: 10px 20px;
238
  }
239
-
240
  /* Img overlay buttons */
241
  #wp_editimgbtn, #wp_delimgbtn, #wp_editgallery, #wp_delgallery {
242
  padding-top: 24px !important;
@@ -260,7 +260,7 @@
260
  #wp_delimgbtn, #wp_delgallery {
261
  background: #eee url("images/delete-2x.png") no-repeat center center !important;
262
  }
263
-
264
  /* AJAX loading spinners */
265
  img.ajax-loading, img.ajax-feedback {
266
  width: 16px;
78
  /* Pointer dismiss button */
79
  .wp-pointer-buttons a.close::before {
80
  background-image: url('images/xit-2x.gif');
81
+ background-size: 20px 10px;
82
  }
83
 
84
  /* Pointer icon */
101
  body.admin-color-classic #screen-meta-links a.show-settings {
102
  background-image: url('images/arrows-vs-2x.png') !important;
103
  }
104
+
105
  /* Collapse button divs */
106
  #collapse-button div {
107
  background-image: url('images/arrows-2x.png') !important;
236
  background-image: url("images/down_arrow-2x.gif") !important;
237
  background-size: 10px 20px;
238
  }
239
+
240
  /* Img overlay buttons */
241
  #wp_editimgbtn, #wp_delimgbtn, #wp_editgallery, #wp_delgallery {
242
  padding-top: 24px !important;
260
  #wp_delimgbtn, #wp_delgallery {
261
  background: #eee url("images/delete-2x.png") no-repeat center center !important;
262
  }
263
+
264
  /* AJAX loading spinners */
265
  img.ajax-loading, img.ajax-feedback {
266
  width: 16px;
_inc/jetpack-rtl.css CHANGED
@@ -45,7 +45,7 @@
45
  }
46
 
47
  .jp-connect { padding: 10px 0 5px !important; }
48
-
49
  #jetpack-settings > .jetpack-message { margin: 10px 15px 10px 13px }
50
 
51
  .jetpack-message .squeezer {
@@ -78,7 +78,7 @@
78
  float: left;
79
  margin: 0 20px 0 30px;
80
  }
81
-
82
  .jetpack-module {
83
  float: right;
84
  margin: 0 15px 15px 0;
45
  }
46
 
47
  .jp-connect { padding: 10px 0 5px !important; }
48
+
49
  #jetpack-settings > .jetpack-message { margin: 10px 15px 10px 13px }
50
 
51
  .jetpack-message .squeezer {
78
  float: left;
79
  margin: 0 20px 0 30px;
80
  }
81
+
82
  .jetpack-module {
83
  float: right;
84
  margin: 0 15px 15px 0;
_inc/jetpack.css CHANGED
@@ -550,7 +550,7 @@ p.jp-help {
550
  border-bottom-left-radius: 3px;
551
  background-repeat: no-repeat;
552
  background-image: url( images/module-icons-sprite.png );
553
- background-size: 2500px 50px; /* remember to update this every time a new module is added! */
554
  }
555
 
556
 
@@ -629,6 +629,13 @@ p.jp-help {
629
  #photon.jetpack-module div.module-image {
630
  background-position: -2320px 5px;
631
  }
 
 
 
 
 
 
 
632
 
633
  .jetpack-module div.module-image p {
634
  background-color: #b4d278;
550
  border-bottom-left-radius: 3px;
551
  background-repeat: no-repeat;
552
  background-image: url( images/module-icons-sprite.png );
553
+ background-size: 2555px 50px; /* remember to update this every time a new module is added! */
554
  }
555
 
556
 
629
  #photon.jetpack-module div.module-image {
630
  background-position: -2320px 5px;
631
  }
632
+ #tiled-gallery.jetpack-module div.module-image {
633
+ background-position: -2400px 5px;
634
+ }
635
+
636
+ #likes.jetpack-module div.module-image {
637
+ background-position: -2471px 5px;
638
+ }
639
 
640
  .jetpack-module div.module-image p {
641
  background-color: #b4d278;
_inc/jquery.inview.js ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * author Christopher Blum
3
+ * - based on the idea of Remy Sharp, http://remysharp.com/2009/01/26/element-in-view-event-plugin/
4
+ * - forked from http://github.com/zuk/jquery.inview/
5
+ */
6
+ (function ($) {
7
+ var inviewObjects = {}, viewportSize, viewportOffset,
8
+ d = document, w = window, documentElement = d.documentElement, expando = $.expando;
9
+
10
+ $.event.special.inview = {
11
+ add: function(data) {
12
+ inviewObjects[data.guid + "-" + this[expando]] = { data: data, $element: $(this) };
13
+ },
14
+
15
+ remove: function(data) {
16
+ try { delete inviewObjects[data.guid + "-" + this[expando]]; } catch(e) {}
17
+ }
18
+ };
19
+
20
+ function getViewportSize() {
21
+ var mode, domObject, size = { height: w.innerHeight, width: w.innerWidth };
22
+
23
+ // if this is correct then return it. iPad has compat Mode, so will
24
+ // go into check clientHeight/clientWidth (which has the wrong value).
25
+ if (!size.height) {
26
+ mode = d.compatMode;
27
+ if (mode || !$.support.boxModel) { // IE, Gecko
28
+ domObject = mode === 'CSS1Compat' ?
29
+ documentElement : // Standards
30
+ d.body; // Quirks
31
+ size = {
32
+ height: domObject.clientHeight,
33
+ width: domObject.clientWidth
34
+ };
35
+ }
36
+ }
37
+
38
+ return size;
39
+ }
40
+
41
+ function getViewportOffset() {
42
+ return {
43
+ top: w.pageYOffset || documentElement.scrollTop || d.body.scrollTop,
44
+ left: w.pageXOffset || documentElement.scrollLeft || d.body.scrollLeft
45
+ };
46
+ }
47
+
48
+ function checkInView() {
49
+ var $elements = $(), elementsLength, i = 0;
50
+
51
+ $.each(inviewObjects, function(i, inviewObject) {
52
+ var selector = inviewObject.data.selector,
53
+ $element = inviewObject.$element;
54
+ $elements = $elements.add(selector ? $element.find(selector) : $element);
55
+ });
56
+
57
+ elementsLength = $elements.length;
58
+ if (elementsLength) {
59
+ viewportSize = viewportSize || getViewportSize();
60
+ viewportOffset = viewportOffset || getViewportOffset();
61
+
62
+ for (; i<elementsLength; i++) {
63
+ // Ignore elements that are not in the DOM tree
64
+ if (!$.contains(documentElement, $elements[i])) {
65
+ continue;
66
+ }
67
+
68
+ var element = $elements[i],
69
+ $element = $(element),
70
+ elementSize = {},
71
+ elementOffset = {},
72
+ inView = $element.data('inview'),
73
+ visiblePartX,
74
+ visiblePartY,
75
+ visiblePartsMerged;
76
+
77
+ // for the case where 'display:none' is used in place of 'visibility:hidden'
78
+ // count and sum the above items to get and move closer to the correct values
79
+ // IMPORTANT :: insert element into container empty
80
+ if($element.css('display') == 'none')
81
+ {
82
+ var parentElement = $element.parent();
83
+
84
+ elementOffset.top = parentElement.offset().top;
85
+ elementOffset.left = parentElement.offset().left;
86
+ elementSize.height = parentElement.height();
87
+ elementSize.width = parentElement.width();
88
+ } else {
89
+ elementSize = { height: $element.height(), width: $element.width() }
90
+ elementOffset = $element.offset();
91
+ }
92
+
93
+ // Don't ask me why because I haven't figured out yet:
94
+ // viewportOffset and viewportSize are sometimes suddenly null in Firefox 5.
95
+ // Even though it sounds weird:
96
+ // It seems that the execution of this function is interferred by the onresize/onscroll event
97
+ // where viewportOffset and viewportSize are unset
98
+ if (!viewportOffset || !viewportSize) {
99
+ return;
100
+ }
101
+
102
+ if (element.offsetWidth >= 0 && element.offsetHeight >= 0 && element.style.display != "none" &&
103
+ elementOffset.top + elementSize.height > viewportOffset.top &&
104
+ elementOffset.top < viewportOffset.top + viewportSize.height &&
105
+ elementOffset.left + elementSize.width > viewportOffset.left &&
106
+ elementOffset.left < viewportOffset.left + viewportSize.width) {
107
+ visiblePartX = (viewportOffset.left > elementOffset.left ?
108
+ 'right' : (viewportOffset.left + viewportSize.width) < (elementOffset.left + elementSize.width) ?
109
+ 'left' : 'both');
110
+ visiblePartY = (viewportOffset.top > elementOffset.top ?
111
+ 'bottom' : (viewportOffset.top + viewportSize.height) < (elementOffset.top + elementSize.height) ?
112
+ 'top' : 'both');
113
+ visiblePartsMerged = visiblePartX + "-" + visiblePartY;
114
+ if (!inView || inView !== visiblePartsMerged) {
115
+ $element.data('inview', visiblePartsMerged).trigger('inview', [true, visiblePartX, visiblePartY]);
116
+ }
117
+ } else if (inView) {
118
+ $element.data('inview', false).trigger('inview', [false]);
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ $(w).bind("scroll resize", function() {
125
+ viewportSize = viewportOffset = null;
126
+ });
127
+
128
+ // IE < 9 scrolls to focused elements without firing the "scroll" event
129
+ if (!documentElement.addEventListener && documentElement.attachEvent) {
130
+ documentElement.attachEvent("onfocusin", function() {
131
+ viewportOffset = null;
132
+ });
133
+ }
134
+
135
+ // Use setInterval in order to also make sure this captures elements within
136
+ // "overflow:scroll" elements or elements that appeared in the dom tree due to
137
+ // dom manipulation and reflow
138
+ // old: $(window).scroll(checkInView);
139
+ //
140
+ // By the way, iOS (iPad, iPhone, ...) seems to not execute, or at least delays
141
+ // intervals while the user scrolls. Therefore the inview event might fire a bit late there
142
+ setInterval(checkInView, 250);
143
+ })(jQuery);
_inc/jquery.jetpack-resize.js ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Resizeable Iframes.
3
+ *
4
+ * Start listening to resize postMessage events for selected iframes:
5
+ * $( selector ).Jetpack( 'resizeable' );
6
+ * - OR -
7
+ * Jetpack.resizeable( 'on', context );
8
+ *
9
+ * Resize selected iframes:
10
+ * $( selector ).Jetpack( 'resizeable', 'resize', { width: 100, height: 200 } );
11
+ * - OR -
12
+ * Jetpack.resizeable( 'resize', { width: 100, height: 200 }, context );
13
+ *
14
+ * Stop listening to resize postMessage events for selected iframes:
15
+ * $( selector ).Jetpack( 'resizeable', 'off' );
16
+ * - OR -
17
+ * Jetpack.resizeable( 'off', context );
18
+ *
19
+ * Stop listening to all resize postMessage events:
20
+ * Jetpack.resizeable( 'off' );
21
+ */
22
+ (function($) {
23
+ var listening = false, // Are we listening for resize postMessage events
24
+ sourceOrigins = [], // What origins are allowed to send resize postMessage events
25
+ $sources = false, // What iframe elements are we tracking resize postMessage events from
26
+
27
+ URLtoOrigin, // Utility to convert URLs into origins
28
+ setupListener, // Binds global resize postMessage event handler
29
+ destroyListener, // Unbinds global resize postMessage event handler
30
+
31
+ methods; // Jetpack.resizeable methods
32
+
33
+ // Setup the Jetpack global
34
+ if ( 'undefined' === typeof window.Jetpack ) {
35
+ window.Jetpack = {
36
+ /**
37
+ * Handles the two different calling methods:
38
+ * $( selector ).Jetpack( 'namespace', 'method', context ) // here, context is optional and is used to filter the collection
39
+ * - vs. -
40
+ * Jetpack.namespace( 'method', context ) // here context defines the collection
41
+ *
42
+ * @internal
43
+ *
44
+ * Call as: Jetpack.getTarget.call( this, context )
45
+ *
46
+ * @param string context: jQuery selector
47
+ * @return jQuery|undefined object on which to perform operations or undefined when context cannot be determined
48
+ */
49
+ getTarget: function( context ) {
50
+ if ( this instanceof jQuery ) {
51
+ return context ? this.filter( context ) : this;
52
+ }
53
+
54
+ return context ? $( context ) : context;
55
+ }
56
+ };
57
+ }
58
+
59
+ // Setup the Jetpack jQuery method
60
+ if ( 'undefined' === typeof $.fn.Jetpack ) {
61
+ /**
62
+ * Dispatches calls to the correct namespace
63
+ *
64
+ * @param string namespace
65
+ * @param ...
66
+ * @return mixed|jQuery (chainable)
67
+ */
68
+ $.fn.Jetpack = function( namespace ) {
69
+ if ( 'function' === typeof Jetpack[namespace] ) {
70
+ // Send the call to the correct Jetpack.namespace
71
+ return Jetpack[namespace].apply( this, Array.prototype.slice.call( arguments, 1 ) );
72
+ } else {
73
+ $.error( 'Namespace "' + namespace + '" does not exist on jQuery.Jetpack' );
74
+ }
75
+ };
76
+ }
77
+
78
+ // Define Jetpack.resizeable() namespace to just always bail if no postMessage
79
+ if ( 'function' !== typeof window.postMessage ) {
80
+ $.extend( window.Jetpack, {
81
+ /**
82
+ * Defines the Jetpack.resizeable() namespace.
83
+ * See below for non-trivial definition for browsers with postMessage.
84
+ */
85
+ resizeable: function() {
86
+ $.error( 'Browser does not support window.postMessage' );
87
+ }
88
+ } );
89
+
90
+ return;
91
+ }
92
+
93
+ /**
94
+ * Utility to convert URLs into origins
95
+ *
96
+ * http://example.com:port/path?query#fragment -> http://example.com:port
97
+ *
98
+ * @param string URL
99
+ * @return string origin
100
+ */
101
+ URLtoOrigin = function( URL ) {
102
+ if ( ! URL.match( /^https?:\/\// ) ) {
103
+ URL = document.location.href;
104
+ }
105
+ return URL.split( '/' ).slice( 0, 3 ).join( '/' );
106
+ };
107
+
108
+ /**
109
+ * Binds global resize postMessage event handler
110
+ */
111
+ setupListener = function() {
112
+ listening = true;
113
+
114
+ $( window ).on( 'message.JetpackResizeableIframe', function( e ) {
115
+ var event = e.originalEvent,
116
+ data;
117
+
118
+ // Ensure origin is allowed
119
+ if ( -1 === $.inArray( event.origin, sourceOrigins ) ) {
120
+ return;
121
+ }
122
+
123
+ // Some browsers send structured data, some send JSON strings
124
+ if ( 'object' === typeof event.data ) {
125
+ data = event.data.data;
126
+ } else {
127
+ try {
128
+ data = JSON.parse( event.data );
129
+ } catch ( err ) {
130
+ data = false;
131
+ }
132
+ }
133
+
134
+ if ( !data.data ) {
135
+ return;
136
+ }
137
+
138
+ // Un-nest
139
+ data = data.data;
140
+
141
+ // Is it a resize event?
142
+ if ( 'undefined' === typeof data.action || 'resize' !== data.action ) {
143
+ return;
144
+ }
145
+
146
+ // Find the correct iframe and resize it
147
+ $sources.filter( function() {
148
+ if ( 'undefined' !== typeof data.name )
149
+ return this.name === data.name;
150
+ else
151
+ return event.source === this.contentWindow;
152
+ } ).first().Jetpack( 'resizeable', 'resize', data );
153
+ } );
154
+ };
155
+
156
+ /**
157
+ * Unbinds global resize postMessage event handler
158
+ */
159
+ destroyListener = function() {
160
+ listening = false;
161
+ $( window ).off( 'message.JetpackResizeableIframe' );
162
+
163
+ sourceOrigins = [];
164
+ $( '.jetpack-resizeable' ).removeClass( 'jetpack-resizeable' );
165
+ $sources = false;
166
+ };
167
+
168
+ // Methods for Jetpack.resizeable() namespace
169
+ methods = {
170
+ /**
171
+ * Start listening for resize postMessage events on the given iframes
172
+ *
173
+ * Call statically as: Jetpack.resizeable( 'on', context )
174
+ * Call as: $( selector ).Jetpack( 'resizeable', 'on', context ) // context optional: used to filter the collectino
175
+ *
176
+ * @param string context jQuery selector.
177
+ * @return jQuery (chainable)
178
+ */
179
+ on: function( context ) {
180
+ var target = Jetpack.getTarget.call( this, context );
181
+
182
+ if ( ! listening ) {
183
+ setupListener();
184
+ }
185
+
186
+ target.each( function() {
187
+ sourceOrigins.push( URLtoOrigin( $( this ).attr( 'src' ) ) );
188
+ } ).addClass( 'jetpack-resizeable' );
189
+
190
+ $sources = $( '.jetpack-resizeable' );
191
+
192
+ return target;
193
+ },
194
+
195
+ /**
196
+ * Stop listening for resize postMessage events on the given iframes
197
+ *
198
+ * Call statically as: Jetpack.resizeable( 'off', context )
199
+ * Call as: $( selector ).Jetpack( 'resizeable', 'off', context ) // context optional: used to filter the collectino
200
+ *
201
+ * @param string context jQuery selector
202
+ * @return jQuery (chainable)
203
+ */
204
+ off: function( context ) {
205
+ var target = Jetpack.getTarget.call( this, context );
206
+
207
+ if ( 'undefined' === typeof target ) {
208
+ destroyListener();
209
+
210
+ return target;
211
+ }
212
+
213
+ target.each( function() {
214
+ var origin = URLtoOrigin( $( this ).attr( 'src' ) ),
215
+ pos = $.inArray( origin, sourceOrigins );
216
+
217
+ if ( -1 !== pos ) {
218
+ sourceOrigins.splice( pos, 1 );
219
+ }
220
+ } ).removeClass( 'jetpack-resizeable' );
221
+
222
+ $sources = $( '.jetpack-resizeable' );
223
+
224
+ return target;
225
+ },
226
+
227
+ /**
228
+ * Resize the given iframes
229
+ *
230
+ * Call statically as: Jetpack.resizeable( 'resize', dimensions, context )
231
+ * Call as: $( selector ).Jetpack( 'resizeable', 'resize', dimensions, context ) // context optional: used to filter the collectino
232
+ *
233
+ * @param object dimensions in pixels: { width: (int), height: (int) }
234
+ * @param string context jQuery selector
235
+ * @return jQuery (chainable)
236
+ */
237
+ resize: function( dimensions, context ) {
238
+ var target = Jetpack.getTarget.call( this, context );
239
+
240
+ $.each( [ 'width', 'height' ], function( i, variable ) {
241
+ var value = 0;
242
+ if ( 'undefined' !== typeof dimensions[variable] ) {
243
+ value = parseInt( dimensions[variable], 10 );
244
+ }
245
+
246
+ if ( 0 !== value ) {
247
+ target[variable]( value );
248
+ var container = target.parent();
249
+ if ( container.hasClass( 'slim-likes-widget' ) ) {
250
+ container[variable]( value );
251
+ }
252
+ }
253
+ } );
254
+
255
+ return target;
256
+ }
257
+ };
258
+
259
+ // Define Jetpack.resizeable() namespace
260
+ $.extend( window.Jetpack, {
261
+ /**
262
+ * Defines the Jetpack.resizeable() namespace.
263
+ * See above for trivial definition for browsers with no postMessage.
264
+ *
265
+ * @param string method
266
+ * @param ...
267
+ * @return mixed|jQuery (chainable)
268
+ */
269
+ resizeable: function( method ) {
270
+ if ( methods[method] ) {
271
+ // Send the call to the correct Jetpack.resizeable() method
272
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
273
+ } else if ( ! method ) {
274
+ // By default, send to Jetpack.resizeable( 'on' ), which isn't useful in that form but is when called as
275
+ // jQuery( selector ).Jetpack( 'resizeable' )
276
+ return methods.on.apply( this );
277
+ } else {
278
+ $.error( 'Method ' + method + ' does not exist on Jetpack.resizeable' );
279
+ }
280
+ }
281
+ } );
282
+ })(jQuery);
_inc/postmessage.js ADDED
@@ -0,0 +1,438 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ The MIT License
3
+
4
+ Copyright (c) 2010 Daniel Park (http://metaweb.com, http://postmessage.freebaseapps.com)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+ **/
24
+ var NO_JQUERY = {};
25
+ (function(window, $, undefined) {
26
+
27
+ if (!("console" in window)) {
28
+ var c = window.console = {};
29
+ c.log = c.warn = c.error = c.debug = function(){};
30
+ }
31
+
32
+ if ($ === NO_JQUERY) {
33
+ // jQuery is optional
34
+ $ = {
35
+ fn: {},
36
+ extend: function() {
37
+ var a = arguments[0];
38
+ for (var i=1,len=arguments.length; i<len; i++) {
39
+ var b = arguments[i];
40
+ for (var prop in b) {
41
+ a[prop] = b[prop];
42
+ }
43
+ }
44
+ return a;
45
+ }
46
+ };
47
+ }
48
+
49
+ $.fn.pm = function() {
50
+ console.log("usage: \nto send: $.pm(options)\nto receive: $.pm.bind(type, fn, [origin])");
51
+ return this;
52
+ };
53
+
54
+ // send postmessage
55
+ $.pm = window.pm = function(options) {
56
+ pm.send(options);
57
+ };
58
+
59
+ // bind postmessage handler
60
+ $.pm.bind = window.pm.bind = function(type, fn, origin, hash, async_reply) {
61
+ pm.bind(type, fn, origin, hash, async_reply === true);
62
+ };
63
+
64
+ // unbind postmessage handler
65
+ $.pm.unbind = window.pm.unbind = function(type, fn) {
66
+ pm.unbind(type, fn);
67
+ };
68
+
69
+ // default postmessage origin on bind
70
+ $.pm.origin = window.pm.origin = null;
71
+
72
+ // default postmessage polling if using location hash to pass postmessages
73
+ $.pm.poll = window.pm.poll = 200;
74
+
75
+ var pm = {
76
+
77
+ send: function(options) {
78
+ var o = $.extend({}, pm.defaults, options),
79
+ target = o.target;
80
+ if (!o.target) {
81
+ console.warn("postmessage target window required");
82
+ return;
83
+ }
84
+ if (!o.type) {
85
+ console.warn("postmessage type required");
86
+ return;
87
+ }
88
+ var msg = {data:o.data, type:o.type};
89
+ if (o.success) {
90
+ msg.callback = pm._callback(o.success);
91
+ }
92
+ if (o.error) {
93
+ msg.errback = pm._callback(o.error);
94
+ }
95
+ if (("postMessage" in target) && !o.hash) {
96
+ pm._bind();
97
+ target.postMessage(JSON.stringify(msg), o.origin || '*');
98
+ }
99
+ else {
100
+ pm.hash._bind();
101
+ pm.hash.send(o, msg);
102
+ }
103
+ },
104
+
105
+ bind: function(type, fn, origin, hash, async_reply) {
106
+ pm._replyBind ( type, fn, origin, hash, async_reply );
107
+ },
108
+
109
+ _replyBind: function(type, fn, origin, hash, isCallback) {
110
+ if (("postMessage" in window) && !hash) {
111
+ pm._bind();
112
+ }
113
+ else {
114
+ pm.hash._bind();
115
+ }
116
+ var l = pm.data("listeners.postmessage");
117
+ if (!l) {
118
+ l = {};
119
+ pm.data("listeners.postmessage", l);
120
+ }
121
+ var fns = l[type];
122
+ if (!fns) {
123
+ fns = [];
124
+ l[type] = fns;
125
+ }
126
+ fns.push({fn:fn, callback: isCallback, origin:origin || $.pm.origin});
127
+ },
128
+
129
+ unbind: function(type, fn) {
130
+ var l = pm.data("listeners.postmessage");
131
+ if (l) {
132
+ if (type) {
133
+ if (fn) {
134
+ // remove specific listener
135
+ var fns = l[type];
136
+ if (fns) {
137
+ var m = [];
138
+ for (var i=0,len=fns.length; i<len; i++) {
139
+ var o = fns[i];
140
+ if (o.fn !== fn) {
141
+ m.push(o);
142
+ }
143
+ }
144
+ l[type] = m;
145
+ }
146
+ }
147
+ else {
148
+ // remove all listeners by type
149
+ delete l[type];
150
+ }
151
+ }
152
+ else {
153
+ // unbind all listeners of all type
154
+ for (var i in l) {
155
+ delete l[i];
156
+ }
157
+ }
158
+ }
159
+ },
160
+
161
+ data: function(k, v) {
162
+ if (v === undefined) {
163
+ return pm._data[k];
164
+ }
165
+ pm._data[k] = v;
166
+ return v;
167
+ },
168
+
169
+ _data: {},
170
+
171
+ _CHARS: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
172
+
173
+ _random: function() {
174
+ var r = [];
175
+ for (var i=0; i<32; i++) {
176
+ r[i] = pm._CHARS[0 | Math.random() * 32];
177
+ };
178
+ return r.join("");
179
+ },
180
+
181
+ _callback: function(fn) {
182
+ var cbs = pm.data("callbacks.postmessage");
183
+ if (!cbs) {
184
+ cbs = {};
185
+ pm.data("callbacks.postmessage", cbs);
186
+ }
187
+ var r = pm._random();
188
+ cbs[r] = fn;
189
+ return r;
190
+ },
191
+
192
+ _bind: function() {
193
+ // are we already listening to message events on this w?
194
+ if (!pm.data("listening.postmessage")) {
195
+ if (window.addEventListener) {
196
+ window.addEventListener("message", pm._dispatch, false);
197
+ }
198
+ else if (window.attachEvent) {
199
+ window.attachEvent("onmessage", pm._dispatch);
200
+ }
201
+ pm.data("listening.postmessage", 1);
202
+ }
203
+ },
204
+
205
+ _dispatch: function(e) {
206
+ //console.log("$.pm.dispatch", e, this);
207
+ try {
208
+ var msg = JSON.parse(e.data);
209
+ }
210
+ catch (ex) {
211
+ //console.warn("postmessage data invalid json: ", ex); //message wasn't meant for pm
212
+ return;
213
+ }
214
+ if (!msg.type) {
215
+ //console.warn("postmessage message type required"); //message wasn't meant for pm
216
+ return;
217
+ }
218
+ var cbs = pm.data("callbacks.postmessage") || {},
219
+ cb = cbs[msg.type];
220
+ if (cb) {
221
+ cb(msg.data);
222
+ }
223
+ else {
224
+ var l = pm.data("listeners.postmessage") || {};
225
+ var fns = l[msg.type] || [];
226
+ for (var i=0,len=fns.length; i<len; i++) {
227
+ var o = fns[i];
228
+ if (o.origin && o.origin !== '*' && e.origin !== o.origin) {
229
+ console.warn("postmessage message origin mismatch", e.origin, o.origin);
230
+ if (msg.errback) {
231
+ // notify post message errback
232
+ var error = {
233
+ message: "postmessage origin mismatch",
234
+ origin: [e.origin, o.origin]
235
+ };
236
+ pm.send({target:e.source, data:error, type:msg.errback});
237
+ }
238
+ continue;
239
+ }
240
+
241
+ function sendReply ( data ) {
242
+ if (msg.callback) {
243
+ pm.send({target:e.source, data:data, type:msg.callback});
244
+ }
245
+ }
246
+
247
+ try {
248
+ if ( o.callback ) {
249
+ o.fn(msg.data, sendReply, e);
250
+ } else {
251
+ sendReply ( o.fn(msg.data, e) );
252
+ }
253
+ }
254
+ catch (ex) {
255
+ if (msg.errback) {
256
+ // notify post message errback
257
+ pm.send({target:e.source, data:ex, type:msg.errback});
258
+ } else {
259
+ throw ex;
260
+ }
261
+ }
262
+ };
263
+ }
264
+ }
265
+ };
266
+
267
+ // location hash polling
268
+ pm.hash = {
269
+
270
+ send: function(options, msg) {
271
+ //console.log("hash.send", target_window, options, msg);
272
+ var target_window = options.target,
273
+ target_url = options.url;
274
+ if (!target_url) {
275
+ console.warn("postmessage target window url is required");
276
+ return;
277
+ }
278
+ target_url = pm.hash._url(target_url);
279
+ var source_window,
280
+ source_url = pm.hash._url(window.location.href);
281
+ if (window == target_window.parent) {
282
+ source_window = "parent";
283
+ }
284
+ else {
285
+ try {
286
+ for (var i=0,len=parent.frames.length; i<len; i++) {
287
+ var f = parent.frames[i];
288
+ if (f == window) {
289
+ source_window = i;
290
+ break;
291
+ }
292
+ };
293
+ }
294
+ catch(ex) {
295
+ // Opera: security error trying to access parent.frames x-origin
296
+ // juse use window.name
297
+ source_window = window.name;
298
+ }
299
+ }
300
+ if (source_window == null) {
301
+ console.warn("postmessage windows must be direct parent/child windows and the child must be available through the parent window.frames list");
302
+ return;
303
+ }
304
+ var hashmessage = {
305
+ "x-requested-with": "postmessage",
306
+ source: {
307
+ name: source_window,
308
+ url: source_url
309
+ },
310
+ postmessage: msg
311
+ };
312
+ var hash_id = "#x-postmessage-id=" + pm._random();
313
+ target_window.location = target_url + hash_id + encodeURIComponent(JSON.stringify(hashmessage));
314
+ },
315
+
316
+ _regex: /^\#x\-postmessage\-id\=(\w{32})/,
317
+
318
+ _regex_len: "#x-postmessage-id=".length + 32,
319
+
320
+ _bind: function() {
321
+ // are we already listening to message events on this w?
322
+ if (!pm.data("polling.postmessage")) {
323
+ setInterval(function() {
324
+ var hash = "" + window.location.hash,
325
+ m = pm.hash._regex.exec(hash);
326
+ if (m) {
327
+ var id = m[1];
328
+ if (pm.hash._last !== id) {
329
+ pm.hash._last = id;
330
+ pm.hash._dispatch(hash.substring(pm.hash._regex_len));
331
+ }
332
+ }
333
+ }, $.pm.poll || 200);
334
+ pm.data("polling.postmessage", 1);
335
+ }
336
+ },
337
+
338
+ _dispatch: function(hash) {
339
+ if (!hash) {
340
+ return;
341
+ }
342
+ try {
343
+ hash = JSON.parse(decodeURIComponent(hash));
344
+ if (!(hash['x-requested-with'] === 'postmessage' &&
345
+ hash.source && hash.source.name != null && hash.source.url && hash.postmessage)) {
346
+ // ignore since hash could've come from somewhere else
347
+ return;
348
+ }
349
+ }
350
+ catch (ex) {
351
+ // ignore since hash could've come from somewhere else
352
+ return;
353
+ }
354
+ var msg = hash.postmessage,
355
+ cbs = pm.data("callbacks.postmessage") || {},
356
+ cb = cbs[msg.type];
357
+ if (cb) {
358
+ cb(msg.data);
359
+ }
360
+ else {
361
+ var source_window;
362
+ if (hash.source.name === "parent") {
363
+ source_window = window.parent;
364
+ }
365
+ else {
366
+ source_window = window.frames[hash.source.name];
367
+ }
368
+ var l = pm.data("listeners.postmessage") || {};
369
+ var fns = l[msg.type] || [];
370
+ for (var i=0,len=fns.length; i<len; i++) {
371
+ var o = fns[i];
372
+ if (o.origin) {
373
+ var origin = /https?\:\/\/[^\/]*/.exec(hash.source.url)[0];
374
+ if (o.origin !== '*' && origin !== o.origin) {
375
+ console.warn("postmessage message origin mismatch", origin, o.origin);
376
+ if (msg.errback) {
377
+ // notify post message errback
378
+ var error = {
379
+ message: "postmessage origin mismatch",
380
+ origin: [origin, o.origin]
381
+ };
382
+ pm.send({target:source_window, data:error, type:msg.errback, hash:true, url:hash.source.url});
383
+ }
384
+ continue;
385
+ }
386
+ }
387
+
388
+ function sendReply ( data ) {
389
+ if (msg.callback) {
390
+ pm.send({target:source_window, data:data, type:msg.callback, hash:true, url:hash.source.url});
391
+ }
392
+ }
393
+
394
+ try {
395
+ if ( o.callback ) {
396
+ o.fn(msg.data, sendReply);
397
+ } else {
398
+ sendReply ( o.fn(msg.data) );
399
+ }
400
+ }
401
+ catch (ex) {
402
+ if (msg.errback) {
403
+ // notify post message errback
404
+ pm.send({target:source_window, data:ex, type:msg.errback, hash:true, url:hash.source.url});
405
+ } else {
406
+ throw ex;
407
+ }
408
+ }
409
+ };
410
+ }
411
+ },
412
+
413
+ _url: function(url) {
414
+ // url minus hash part
415
+ return (""+url).replace(/#.*$/, "");
416
+ }
417
+
418
+ };
419
+
420
+ $.extend(pm, {
421
+ defaults: {
422
+ target: null, /* target window (required) */
423
+ url: null, /* target window url (required if no window.postMessage or hash == true) */
424
+ type: null, /* message type (required) */
425
+ data: null, /* message data (required) */
426
+ success: null, /* success callback (optional) */
427
+ error: null, /* error callback (optional) */
428
+ origin: "*", /* postmessage origin (optional) */
429
+ hash: false /* use location hash for message passing (optional) */
430
+ }
431
+ });
432
+
433
+ })(this, typeof jQuery === "undefined" ? NO_JQUERY : jQuery);
434
+
435
+ /**
436
+ * http://www.JSON.org/json2.js
437
+ **/
438
+ if (! ("JSON" in window && window.JSON)){JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
class.jetpack-bbpress-json-api-compat.php ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * bbPress & Jetpack REST API Compatibility
4
+ * Enables bbPress to work with the Jetpack REST API
5
+ */
6
+ class bbPress_Jetpack_REST_API {
7
+
8
+ private static $instance;
9
+
10
+ public static function instance() {
11
+ if ( isset( self::$instance ) )
12
+ return self::$instance;
13
+
14
+ self::$instance = new self;
15
+ }
16
+
17
+ private function __construct() {
18
+ add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_bbpress_post_types' ) );
19
+ add_filter( 'bbp_map_meta_caps', array( $this, 'adjust_meta_caps' ), 10, 4 );
20
+ add_filter( 'rest_api_allowed_public_metadata', array( $this, 'allow_bbpress_public_metadata' ) );
21
+ }
22
+
23
+ function allow_bbpress_post_types( $allowed_post_types ) {
24
+
25
+ // only run for REST API requests
26
+ if ( ! defined( 'REST_API_REQUEST' ) || ! REST_API_REQUEST )
27
+ return $allowed_post_types;
28
+
29
+ $allowed_post_types[] = 'forum';
30
+ $allowed_post_types[] = 'topic';
31
+ $allowed_post_types[] = 'reply';
32
+ return $allowed_post_types;
33
+ }
34
+
35
+ function allow_bbpress_public_metadata( $allowed_meta_keys ) {
36
+
37
+ // only run for REST API requests
38
+ if ( ! defined( 'REST_API_REQUEST' ) || ! REST_API_REQUEST )
39
+ return $allowed_meta_keys;
40
+
41
+ $allowed_meta_keys[] = '_bbp_forum_id';
42
+ $allowed_meta_keys[] = '_bbp_topic_id';
43
+ $allowed_meta_keys[] = '_bbp_status';
44
+ $allowed_meta_keys[] = '_bbp_forum_type';
45
+ $allowed_meta_keys[] = '_bbp_forum_subforum_count';
46
+ $allowed_meta_keys[] = '_bbp_reply_count';
47
+ $allowed_meta_keys[] = '_bbp_total_reply_count';
48
+ $allowed_meta_keys[] = '_bbp_topic_count';
49
+ $allowed_meta_keys[] = '_bbp_total_topic_count';
50
+ $allowed_meta_keys[] = '_bbp_topic_count_hidden';
51
+ $allowed_meta_keys[] = '_bbp_last_topic_id';
52
+ $allowed_meta_keys[] = '_bbp_last_reply_id';
53
+ $allowed_meta_keys[] = '_bbp_last_active_time';
54
+ $allowed_meta_keys[] = '_bbp_last_active_id';
55
+ $allowed_meta_keys[] = '_bbp_sticky_topics';
56
+ $allowed_meta_keys[] = '_bbp_voice_count';
57
+ $allowed_meta_keys[] = '_bbp_reply_count_hidden';
58
+ $allowed_meta_keys[] = '_bbp_anonymous_reply_count';
59
+
60
+ return $allowed_meta_keys;
61
+ }
62
+
63
+ function adjust_meta_caps( $caps, $cap, $user_id, $args ) {
64
+
65
+ // only run for REST API requests
66
+ if ( ! defined( 'REST_API_REQUEST' ) || ! REST_API_REQUEST )
67
+ return $caps;
68
+
69
+ // only modify caps for meta caps and for bbPress meta keys
70
+ if ( ! in_array( $cap, array( 'edit_post_meta', 'delete_post_meta', 'add_post_meta' ) ) || empty( $args[1] ) || false === strpos( $args[1], '_bbp_' ) )
71
+ return $caps;
72
+
73
+ // $args[0] could be a post ID or a post_type string
74
+ if ( is_int( $args[0] ) ) {
75
+ $_post = get_post( $args[0] );
76
+ if ( ! empty( $_post ) ) {
77
+ $post_type = get_post_type_object( $_post->post_type );
78
+ }
79
+ } elseif ( is_string( $args[0] ) ) {
80
+ $post_type = get_post_type_object( $args[0] );
81
+ }
82
+
83
+ // no post type found, bail
84
+ if ( empty( $post_type ) )
85
+ return $caps;
86
+
87
+ // reset the needed caps
88
+ $caps = array();
89
+
90
+ // Add 'do_not_allow' cap if user is spam or deleted
91
+ if ( bbp_is_user_inactive( $user_id ) ) {
92
+ $caps[] = 'do_not_allow';
93
+
94
+ // Moderators can always edit meta
95
+ } elseif ( user_can( $user_id, 'moderate' ) ) {
96
+ $caps[] = 'moderate';
97
+
98
+ // Unknown so map to edit_posts
99
+ } else {
100
+ $caps[] = $post_type->cap->edit_posts;
101
+ }
102
+
103
+ return $caps;
104
+ }
105
+
106
+ }
107
+
108
+ bbPress_Jetpack_REST_API::instance();
class.jetpack-ixr-client.php CHANGED
@@ -49,7 +49,7 @@ class Jetpack_IXR_Client extends IXR_Client {
49
  $this->error = new IXR_Error( -32300, 'transport error - HTTP status code was not 200' );
50
  return false;
51
  }
52
-
53
  $content = wp_remote_retrieve_body( $response );
54
 
55
  // Now parse what we've got back
49
  $this->error = new IXR_Error( -32300, 'transport error - HTTP status code was not 200' );
50
  return false;
51
  }
52
+
53
  $content = wp_remote_retrieve_body( $response );
54
 
55
  // Now parse what we've got back
class.jetpack-post-images.php CHANGED
@@ -15,15 +15,17 @@ class Jetpack_PostImages {
15
  * If a slideshow is embedded within a post, then parse out the images involved and return them
16
  */
17
  static function from_slideshow( $post_id, $width = 200, $height = 200 ) {
 
 
18
  $post = get_post( $post_id );
 
 
19
 
20
  if ( false === strpos( $post->post_content, '[slideshow' ) )
21
  return false; // no slideshow - bail
22
 
23
  $permalink = get_permalink( $post->ID );
24
 
25
- $images = array();
26
-
27
  // Mechanic: Somebody set us up the bomb
28
  $old_post = $GLOBALS['post'];
29
  $GLOBALS['post'] = $post;
@@ -79,15 +81,17 @@ class Jetpack_PostImages {
79
  * If a gallery is detected, then get all the images from it.
80
  */
81
  static function from_gallery( $post_id ) {
 
 
82
  $post = get_post( $post_id );
 
 
83
 
84
  if ( false === strpos( $post->post_content, '[gallery' ) )
85
  return false; // no gallery - bail
86
 
87
  $permalink = get_permalink( $post->ID );
88
 
89
- $images = array();
90
-
91
  // CATS: All your base are belong to us
92
  $old_post = $GLOBALS['post'];
93
  $GLOBALS['post'] = $post;
@@ -145,6 +149,11 @@ class Jetpack_PostImages {
145
  * their dimensions are at or above a required minimum.
146
  */
147
  static function from_attachment( $post_id, $width = 200, $height = 200 ) {
 
 
 
 
 
148
 
149
  $post_images = get_posts( array(
150
  'post_parent' => $post_id, // Must be children of post
@@ -158,8 +167,6 @@ class Jetpack_PostImages {
158
 
159
  $permalink = get_permalink( $post_id );
160
 
161
- $images = array();
162
-
163
  foreach ( $post_images as $post_image ) {
164
  $meta = wp_get_attachment_metadata( $post_image->ID );
165
  // Must be larger than 200x200
@@ -186,7 +193,7 @@ class Jetpack_PostImages {
186
  * compare URLs to see if an image is attached AND inserted.
187
  */
188
  $html_images = array();
189
- $html_images = self::from_html( get_post( $post_id ) );
190
  $inserted_images = array();
191
 
192
  foreach( $html_images as $html_image ) {
@@ -210,9 +217,12 @@ class Jetpack_PostImages {
210
  static function from_thumbnail( $post_id, $width = 200, $height = 200 ) {
211
  $images = array();
212
 
213
- if ( !function_exists( 'get_post_thumbnail_id' ) ) {
 
 
 
 
214
  return $images;
215
- }
216
 
217
  $thumb = get_post_thumbnail_id( $post_id );
218
 
@@ -243,19 +253,23 @@ class Jetpack_PostImages {
243
 
244
  /**
245
  * Very raw -- just parse the HTML and pull out any/all img tags and return their src
246
- * @param str $html The HTML string to parse for images, or a post object
247
  * @return Array containing images
248
  */
249
- static function from_html( $html ) {
250
  $images = array();
251
 
252
- if ( is_object( $html ) ) {
253
- if ( property_exists( $html, 'post_content' ) )
254
- $html = apply_filters( 'the_content', $html->post_content );
255
- else
256
  return $images;
 
 
257
  }
258
 
 
 
 
259
  preg_match_all( '!<img.*src="([^"]+)".*/?>!iUs', $html, $matches );
260
  if ( !empty( $matches[1] ) ) {
261
  foreach ( $matches[1] as $match ) {
@@ -358,8 +372,10 @@ class Jetpack_PostImages {
358
  */
359
  static function get_image( $post_id, $args = array() ) {
360
  $image = '';
 
361
  $media = self::get_images( $post_id, $args );
362
 
 
363
  if ( is_array( $media ) ) {
364
  foreach ( $media as $item ) {
365
  if ( 'image' == $item['type'] ) {
@@ -369,6 +385,8 @@ class Jetpack_PostImages {
369
  }
370
  }
371
 
 
 
372
  return $image;
373
  }
374
 
@@ -376,7 +394,7 @@ class Jetpack_PostImages {
376
  * Get an array containing a collection of possible images for this post, stopping once we hit a method
377
  * that returns something useful.
378
  * @param int $post_id
379
- * @param array $args Optional args, curently only width and height required for images
380
  * @return Array containing images that would be good for representing this post
381
  */
382
  static function get_images( $post_id, $args = array() ) {
@@ -388,23 +406,38 @@ class Jetpack_PostImages {
388
  return $media;
389
 
390
  $defaults = array(
391
- 'width' => 200, // Required minimum width (if possible to determine)
392
  'height' => 200, // Required minimum height (if possible to determine)
393
- 'avatar_size' => 96,
394
- 'fallback_to_avatars' => false,
395
- 'gravatar_default' => false,
 
 
 
 
 
 
 
 
 
396
  );
397
  $args = wp_parse_args( $args, $defaults );
398
 
399
- $media = self::from_thumbnail( $post_id, $args['width'], $args['height'] );
400
- if ( !$media )
 
 
401
  $media = self::from_slideshow( $post_id, $args['width'], $args['height'] );
402
- if ( !$media )
403
  $media = self::from_gallery( $post_id );
404
- if ( !$media )
405
  $media = self::from_attachment( $post_id, $args['width'], $args['height'] );
406
- if ( !$media )
407
- $media = self::from_html( get_post( $post_id ) );
 
 
 
 
408
 
409
  if ( !$media && $args['fallback_to_avatars'] ) {
410
  $media = self::from_blavatar( $post_id, $args['avatar_size'] );
15
  * If a slideshow is embedded within a post, then parse out the images involved and return them
16
  */
17
  static function from_slideshow( $post_id, $width = 200, $height = 200 ) {
18
+ $images = array();
19
+
20
  $post = get_post( $post_id );
21
+ if ( !empty( $post->post_password ) )
22
+ return $images;
23
 
24
  if ( false === strpos( $post->post_content, '[slideshow' ) )
25
  return false; // no slideshow - bail
26
 
27
  $permalink = get_permalink( $post->ID );
28
 
 
 
29
  // Mechanic: Somebody set us up the bomb
30
  $old_post = $GLOBALS['post'];
31
  $GLOBALS['post'] = $post;
81
  * If a gallery is detected, then get all the images from it.
82
  */
83
  static function from_gallery( $post_id ) {
84
+ $images = array();
85
+
86
  $post = get_post( $post_id );
87
+ if ( !empty( $post->post_password ) )
88
+ return $images;
89
 
90
  if ( false === strpos( $post->post_content, '[gallery' ) )
91
  return false; // no gallery - bail
92
 
93
  $permalink = get_permalink( $post->ID );
94
 
 
 
95
  // CATS: All your base are belong to us
96
  $old_post = $GLOBALS['post'];
97
  $GLOBALS['post'] = $post;
149
  * their dimensions are at or above a required minimum.
150
  */
151
  static function from_attachment( $post_id, $width = 200, $height = 200 ) {
152
+ $images = array();
153
+
154
+ $post = get_post( $post_id );
155
+ if ( !empty( $post->post_password ) )
156
+ return $images;
157
 
158
  $post_images = get_posts( array(
159
  'post_parent' => $post_id, // Must be children of post
167
 
168
  $permalink = get_permalink( $post_id );
169
 
 
 
170
  foreach ( $post_images as $post_image ) {
171
  $meta = wp_get_attachment_metadata( $post_image->ID );
172
  // Must be larger than 200x200
193
  * compare URLs to see if an image is attached AND inserted.
194
  */
195
  $html_images = array();
196
+ $html_images = self::from_html( $post_id );
197
  $inserted_images = array();
198
 
199
  foreach( $html_images as $html_image ) {
217
  static function from_thumbnail( $post_id, $width = 200, $height = 200 ) {
218
  $images = array();
219
 
220
+ $post = get_post( $post_id );
221
+ if ( !empty( $post->post_password ) )
222
+ return $images;
223
+
224
+ if ( !function_exists( 'get_post_thumbnail_id' ) )
225
  return $images;
 
226
 
227
  $thumb = get_post_thumbnail_id( $post_id );
228
 
253
 
254
  /**
255
  * Very raw -- just parse the HTML and pull out any/all img tags and return their src
256
+ * @param mixed $html_or_id The HTML string to parse for images, or a post id
257
  * @return Array containing images
258
  */
259
+ static function from_html( $html_or_id ) {
260
  $images = array();
261
 
262
+ if ( is_numeric( $html_or_id ) ) {
263
+ $post = get_post( $html_or_id );
264
+ if ( empty( $post ) || !empty( $post->post_password ) )
 
265
  return $images;
266
+
267
+ $html = $post->post_content; // DO NOT apply the_content filters here, it will cause loops
268
  }
269
 
270
+ if ( !$html )
271
+ return $images;
272
+
273
  preg_match_all( '!<img.*src="([^"]+)".*/?>!iUs', $html, $matches );
274
  if ( !empty( $matches[1] ) ) {
275
  foreach ( $matches[1] as $match ) {
372
  */
373
  static function get_image( $post_id, $args = array() ) {
374
  $image = '';
375
+ do_action( 'jetpack_postimages_pre_get_image', $post_id );
376
  $media = self::get_images( $post_id, $args );
377
 
378
+
379
  if ( is_array( $media ) ) {
380
  foreach ( $media as $item ) {
381
  if ( 'image' == $item['type'] ) {
385
  }
386
  }
387
 
388
+ do_action( 'jetpack_postimages_post_get_image', $post_id );
389
+
390
  return $image;
391
  }
392
 
394
  * Get an array containing a collection of possible images for this post, stopping once we hit a method
395
  * that returns something useful.
396
  * @param int $post_id
397
+ * @param array $args Optional args, see defaults list for details
398
  * @return Array containing images that would be good for representing this post
399
  */
400
  static function get_images( $post_id, $args = array() ) {
406
  return $media;
407
 
408
  $defaults = array(
409
+ 'width' => 200, // Required minimum width (if possible to determine)
410
  'height' => 200, // Required minimum height (if possible to determine)
411
+
412
+ 'fallback_to_avatars' => false, // Optionally include Blavatar and Gravatar (in that order) in the image stack
413
+ 'avatar_size' => 96, // Used for both Grav and Blav
414
+ 'gravatar_default' => false, // Default image to use if we end up with no Gravatar
415
+
416
+ 'from_thumbnail' => true, // Use these flags to specifcy which methods to use to find an image
417
+ 'from_slideshow' => true,
418
+ 'from_gallery' => true,
419
+ 'from_attachment' => true,
420
+ 'from_html' => true,
421
+
422
+ 'html_content' => '' // HTML string to pass to from_html()
423
  );
424
  $args = wp_parse_args( $args, $defaults );
425
 
426
+ $media = false;
427
+ if ( $args['from_thumbnail'] )
428
+ $media = self::from_thumbnail( $post_id, $args['width'], $args['height'] );
429
+ if ( !$media && $args['from_slideshow'] )
430
  $media = self::from_slideshow( $post_id, $args['width'], $args['height'] );
431
+ if ( !$media && $args['from_gallery'] )
432
  $media = self::from_gallery( $post_id );
433
+ if ( !$media && $args['from_attachment'] )
434
  $media = self::from_attachment( $post_id, $args['width'], $args['height'] );
435
+ if ( !$media && $args['from_html'] ) {
436
+ if ( empty( $args['html_content'] ) )
437
+ $media = self::from_html( $post_id ); // Use the post_id, which will load the content
438
+ else
439
+ $media = self::from_html( $args['html_content'] ); // If html_content is provided, use that
440
+ }
441
 
442
  if ( !$media && $args['fallback_to_avatars'] ) {
443
  $media = self::from_blavatar( $post_id, $args['avatar_size'] );
class.jetpack-signature.php CHANGED
@@ -56,7 +56,7 @@ class Jetpack_Signature {
56
  }
57
  }
58
 
59
- $method = isset( $override['method'] ) ? $override['method'] : $_SERVER['REQUEST_METHOD'];
60
  return $this->sign_request( $a['token'], $a['timestamp'], $a['nonce'], $a['body-hash'], $method, $url, $body, true );
61
  }
62
 
@@ -99,7 +99,7 @@ class Jetpack_Signature {
99
  return new Jetpack_Error( 'invalid_body_hash', 'The body hash does not match.' );
100
  }
101
  } else {
102
- if ( $verify_body_hash && jetpack_sha1_base64( $body ) != $body_hash ) {
103
  return new Jetpack_Error( 'invalid_body_hash', 'The body hash does not match.' );
104
  }
105
  }
56
  }
57
  }
58
 
59
+ $method = isset( $override['method'] ) ? $override['method'] : $_SERVER['REQUEST_METHOD'];
60
  return $this->sign_request( $a['token'], $a['timestamp'], $a['nonce'], $a['body-hash'], $method, $url, $body, true );
61
  }
62
 
99
  return new Jetpack_Error( 'invalid_body_hash', 'The body hash does not match.' );
100
  }
101
  } else {
102
+ if ( $verify_body_hash && jetpack_sha1_base64( $body ) !== $body_hash ) {
103
  return new Jetpack_Error( 'invalid_body_hash', 'The body hash does not match.' );
104
  }
105
  }
class.jetpack-xmlrpc-server.php CHANGED
@@ -30,7 +30,7 @@ class Jetpack_XMLRPC_Server {
30
  'jetpack.featuresEnabled' => array( $this, 'features_enabled' ),
31
  'jetpack.getPost' => array( $this, 'get_post' ),
32
  'jetpack.getPosts' => array( $this, 'get_posts' ),
33
- 'jetpack.getComment' => array( $this, 'get_comment' ),
34
  'jetpack.getComments' => array( $this, 'get_comments' ),
35
  ) );
36
 
@@ -157,7 +157,7 @@ class Jetpack_XMLRPC_Server {
157
  function test_connection() {
158
  return JETPACK__VERSION;
159
  }
160
-
161
  function test_api_user_code( $args ) {
162
  $client_id = (int) $args[0];
163
  $user_id = (int) $args[1];
@@ -180,7 +180,7 @@ class Jetpack_XMLRPC_Server {
180
  error_log( "VERIFY: $verify" );
181
  */
182
 
183
- $jetpack_token = Jetpack_Data::get_access_token( 1 );
184
 
185
  $api_user_code = get_user_meta( $user_id, "jetpack_json_api_$client_id", true );
186
  if ( !$api_user_code ) {
@@ -278,7 +278,7 @@ class Jetpack_XMLRPC_Server {
278
 
279
  return $sync_data;
280
  }
281
-
282
  function update_attachment_parent( $args ) {
283
  $attachment_id = (int) $args[0];
284
  $parent_id = (int) $args[1];
30
  'jetpack.featuresEnabled' => array( $this, 'features_enabled' ),
31
  'jetpack.getPost' => array( $this, 'get_post' ),
32
  'jetpack.getPosts' => array( $this, 'get_posts' ),
33
+ 'jetpack.getComment' => array( $this, 'get_comment' ),
34
  'jetpack.getComments' => array( $this, 'get_comments' ),
35
  ) );
36
 
157
  function test_connection() {
158
  return JETPACK__VERSION;
159
  }
160
+
161
  function test_api_user_code( $args ) {
162
  $client_id = (int) $args[0];
163
  $user_id = (int) $args[1];
180
  error_log( "VERIFY: $verify" );
181
  */
182
 
183
+ $jetpack_token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
184
 
185
  $api_user_code = get_user_meta( $user_id, "jetpack_json_api_$client_id", true );
186
  if ( !$api_user_code ) {
278
 
279
  return $sync_data;
280
  }
281
+
282
  function update_attachment_parent( $args ) {
283
  $attachment_id = (int) $args[0];
284
  $parent_id = (int) $args[1];
class.json-api-endpoints.php CHANGED
@@ -55,7 +55,7 @@ abstract class WPCOM_JSON_API_Endpoint {
55
 
56
  // Is this endpoint still in testing phase? If so, not available to the public.
57
  var $in_testing = false;
58
-
59
  /**
60
  * @var string Version of the API
61
  */
@@ -163,6 +163,7 @@ abstract class WPCOM_JSON_API_Endpoint {
163
  $input = trim( $this->api->post_body );
164
 
165
  switch ( $this->api->content_type ) {
 
166
  case 'application/json' :
167
  case 'application/x-javascript' :
168
  case 'text/javascript' :
@@ -446,6 +447,16 @@ abstract class WPCOM_JSON_API_Endpoint {
446
  );
447
  $return[$key] = (object) $this->cast_and_filter( $value, apply_filters( 'wpcom_json_api_attachment_cast_and_filter', $docs ), false, $for_output );
448
  break;
 
 
 
 
 
 
 
 
 
 
449
  default :
450
  trigger_error( "Unknown API casting type {$type['type']}", E_USER_WARNING );
451
  }