PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.0.3
Jetpack – WP Security, Backup, Speed, & Growth v12.0.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / related-posts / related-posts.js
jetpack / modules / related-posts Last commit date
rtl 11 years ago class.related-posts-customize.php 3 years ago jetpack-related-posts.php 3 years ago related-posts-customizer.js 6 years ago related-posts-rtl.css 4 years ago related-posts.css 4 years ago related-posts.js 4 years ago
related-posts.js
389 lines
1 /* globals related_posts_js_options */
2
3 /**
4 * Load related posts
5 */
6 ( function () {
7 'use strict';
8
9 var jprp = {
10 response: null,
11
12 /**
13 * Utility get related posts JSON endpoint from URLs
14 *
15 * @param {string} URL (optional)
16 * @return {string} Endpoint URL
17 */
18 getEndpointURL: function ( URL ) {
19 var locationObject,
20 is_customizer =
21 'undefined' !== typeof wp &&
22 wp.customize &&
23 wp.customize.settings &&
24 wp.customize.settings.url &&
25 wp.customize.settings.url.self;
26
27 // If we're in Customizer, write the correct URL.
28 if ( is_customizer ) {
29 locationObject = document.createElement( 'a' );
30 locationObject.href = wp.customize.settings.url.self;
31 } else {
32 locationObject = document.location;
33 }
34
35 if ( 'string' === typeof URL && URL.match( /^https?:\/\// ) ) {
36 locationObject = document.createElement( 'a' );
37 locationObject.href = URL;
38 }
39
40 var args = 'relatedposts=1';
41 var relatedPosts = document.querySelector( '#jp-relatedposts' );
42
43 if ( ! relatedPosts ) {
44 return false;
45 }
46
47 if ( relatedPosts.hasAttribute( 'data-exclude' ) ) {
48 args += '&relatedposts_exclude=' + relatedPosts.getAttribute( 'data-exclude' );
49 }
50
51 if ( is_customizer ) {
52 args += '&jetpackrpcustomize=1';
53 }
54
55 var pathname = locationObject.pathname;
56 if ( '/' !== pathname[ 0 ] ) {
57 pathname = '/' + pathname;
58 }
59
60 if ( '' === locationObject.search ) {
61 return pathname + '?' + args;
62 } else {
63 return pathname + locationObject.search + '&' + args;
64 }
65 },
66
67 getAnchor: function ( post, classNames ) {
68 var anchorTitle = post.title;
69 var anchor = document.createElement( 'a' );
70 anchor.setAttribute( 'class', classNames );
71 anchor.setAttribute( 'href', post.url );
72 anchor.setAttribute( 'title', anchorTitle );
73 anchor.setAttribute( 'data-origin', post.url_meta.origin );
74 anchor.setAttribute( 'data-position', post.url_meta.position );
75
76 if ( '' !== post.rel ) {
77 anchor.setAttribute( 'rel', post.rel );
78 }
79
80 var div = document.createElement( 'div' );
81 div.appendChild( anchor );
82
83 var anchorHTML = div.innerHTML;
84 return [ anchorHTML.substring( 0, anchorHTML.length - 4 ), '</a>' ];
85 },
86
87 generateMinimalHtml: function ( posts, options ) {
88 var self = this;
89 var html = '';
90
91 posts.forEach( function ( post, index ) {
92 var anchor = self.getAnchor( post, 'jp-relatedposts-post-a' );
93 var classes = 'jp-relatedposts-post jp-relatedposts-post' + index;
94
95 if ( post.classes.length > 0 ) {
96 classes += ' ' + post.classes.join( ' ' );
97 }
98
99 html +=
100 '<p class="' +
101 classes +
102 '" data-post-id="' +
103 post.id +
104 '" data-post-format="' +
105 post.format +
106 '">';
107 html +=
108 '<span class="jp-relatedposts-post-title">' +
109 anchor[ 0 ] +
110 post.title +
111 anchor[ 1 ] +
112 '</span>';
113 if ( options.showDate ) {
114 html +=
115 '<time class="jp-relatedposts-post-date" datetime="' +
116 post.date +
117 '">' +
118 post.date +
119 '</time>';
120 }
121 if ( options.showContext ) {
122 html += '<span class="jp-relatedposts-post-context">' + post.context + '</span>';
123 }
124 html += '</p>';
125 } );
126 return (
127 '<div class="jp-relatedposts-items jp-relatedposts-items-minimal jp-relatedposts-' +
128 options.layout +
129 ' ">' +
130 html +
131 '</div>'
132 );
133 },
134
135 generateVisualHtml: function ( posts, options ) {
136 var self = this;
137 var html = '';
138
139 posts.forEach( function ( post, index ) {
140 var anchor = self.getAnchor( post, 'jp-relatedposts-post-a' );
141 var classes = 'jp-relatedposts-post jp-relatedposts-post' + index;
142
143 if ( post.classes.length > 0 ) {
144 classes += ' ' + post.classes.join( ' ' );
145 }
146
147 if ( ! post.img.src ) {
148 classes += ' jp-relatedposts-post-nothumbs';
149 } else {
150 classes += ' jp-relatedposts-post-thumbs';
151 }
152
153 var dummyContainer = document.createElement( 'p' );
154 dummyContainer.innerHTML = post.excerpt;
155 var excerpt = dummyContainer.textContent;
156
157 html +=
158 '<div class="' +
159 classes +
160 '" data-post-id="' +
161 post.id +
162 '" data-post-format="' +
163 post.format +
164 '">';
165 if ( post.img.src ) {
166 html +=
167 anchor[ 0 ] +
168 '<img class="jp-relatedposts-post-img" loading="lazy" src="' +
169 post.img.src +
170 '" width="' +
171 post.img.width +
172 '" height="' +
173 post.img.height +
174 '" alt="' +
175 post.img.alt_text +
176 '" />' +
177 anchor[ 1 ];
178 } else {
179 var anchor_overlay = self.getAnchor(
180 post,
181 'jp-relatedposts-post-a jp-relatedposts-post-aoverlay'
182 );
183 html += anchor_overlay[ 0 ] + anchor_overlay[ 1 ];
184 }
185 html +=
186 '<' +
187 related_posts_js_options.post_heading +
188 ' class="jp-relatedposts-post-title">' +
189 anchor[ 0 ] +
190 post.title +
191 anchor[ 1 ] +
192 '</' +
193 related_posts_js_options.post_heading +
194 '>';
195 html += '<p class="jp-relatedposts-post-excerpt">' + excerpt + '</p>';
196 if ( options.showDate ) {
197 html +=
198 '<time class="jp-relatedposts-post-date" datetime="' +
199 post.date +
200 '">' +
201 post.date +
202 '</time>';
203 }
204 if ( options.showContext ) {
205 html += '<p class="jp-relatedposts-post-context">' + post.context + '</p>';
206 }
207 html += '</div>';
208 } );
209 return (
210 '<div class="jp-relatedposts-items jp-relatedposts-items-visual jp-relatedposts-' +
211 options.layout +
212 ' ">' +
213 html +
214 '</div>'
215 );
216 },
217
218 /**
219 * We want to set a max height on the excerpt however we want to set
220 * this according to the natual pacing of the page as we never want to
221 * cut off a line of text in the middle so we need to do some detective
222 * work.
223 */
224 setVisualExcerptHeights: function () {
225 var elements = document.querySelectorAll(
226 '#jp-relatedposts .jp-relatedposts-post-nothumbs .jp-relatedposts-post-excerpt'
227 );
228
229 if ( ! elements.length ) {
230 return;
231 }
232
233 var firstElementStyles = getComputedStyle( elements[ 0 ] );
234
235 var fontSize = parseInt( firstElementStyles.fontSize, 10 );
236 var lineHeight = parseInt( firstElementStyles.lineHeight, 10 );
237
238 // Show 5 lines of text
239 for ( var i = 0; i < elements.length; i++ ) {
240 elements[ i ].style.maxHeight = ( 5 * lineHeight ) / fontSize + 'em';
241 }
242 },
243
244 getTrackedUrl: function ( anchor ) {
245 var args = 'relatedposts_hit=1';
246 args += '&relatedposts_origin=' + anchor.getAttribute( 'data-origin' );
247 args += '&relatedposts_position=' + anchor.getAttribute( 'data-position' );
248
249 var pathname = anchor.pathname;
250 if ( '/' !== pathname[ 0 ] ) {
251 pathname = '/' + pathname;
252 }
253
254 if ( '' === anchor.search ) {
255 return pathname + '?' + args;
256 } else {
257 return pathname + anchor.search + '&' + args;
258 }
259 },
260
261 cleanupTrackedUrl: function () {
262 if ( 'function' !== typeof history.replaceState ) {
263 return;
264 }
265
266 var cleaned_search = document.location.search.replace(
267 /\brelatedposts_[a-z]+=[0-9]*&?\b/gi,
268 ''
269 );
270 if ( '?' === cleaned_search ) {
271 cleaned_search = '';
272 }
273 if ( document.location.search !== cleaned_search ) {
274 history.replaceState( {}, document.title, document.location.pathname + cleaned_search );
275 }
276 },
277 };
278
279 function afterPostsHaveLoaded() {
280 jprp.setVisualExcerptHeights();
281 var posts = document.querySelectorAll( '#jp-relatedposts a.jp-relatedposts-post-a' );
282
283 Array.prototype.forEach.call( posts, function ( post ) {
284 document.addEventListener( 'click', function () {
285 post.href = jprp.getTrackedUrl( post );
286 } );
287 } );
288 }
289
290 /**
291 * Initialize Related Posts.
292 */
293 function startRelatedPosts() {
294 jprp.cleanupTrackedUrl();
295
296 var endpointURL = jprp.getEndpointURL();
297 var relatedPosts = document.querySelector( '#jp-relatedposts' );
298
299 if ( ! endpointURL ) {
300 return;
301 }
302
303 if ( document.querySelectorAll( '#jp-relatedposts .jp-relatedposts-post' ).length ) {
304 afterPostsHaveLoaded();
305 return;
306 }
307
308 var request = new XMLHttpRequest();
309 request.open( 'GET', endpointURL, true );
310 request.setRequestHeader( 'x-requested-with', 'XMLHttpRequest' );
311
312 request.onreadystatechange = function () {
313 if ( this.readyState === XMLHttpRequest.DONE && this.status === 200 ) {
314 try {
315 var response = JSON.parse( request.responseText );
316
317 if ( 0 === response.items.length || 0 === relatedPosts.length ) {
318 return;
319 }
320
321 jprp.response = response;
322
323 var html,
324 showThumbnails,
325 options = {};
326
327 if ( 'undefined' !== typeof wp && wp.customize ) {
328 showThumbnails = wp.customize.instance( 'jetpack_relatedposts[show_thumbnails]' ).get();
329 options.showDate = wp.customize.instance( 'jetpack_relatedposts[show_date]' ).get();
330 options.showContext = wp.customize
331 .instance( 'jetpack_relatedposts[show_context]' )
332 .get();
333 options.layout = wp.customize.instance( 'jetpack_relatedposts[layout]' ).get();
334 } else {
335 showThumbnails = response.show_thumbnails;
336 options.showDate = response.show_date;
337 options.showContext = response.show_context;
338 options.layout = response.layout;
339 }
340
341 html = ! showThumbnails
342 ? jprp.generateMinimalHtml( response.items, options )
343 : jprp.generateVisualHtml( response.items, options );
344
345 var div = document.createElement( 'div' );
346 relatedPosts.appendChild( div );
347 div.outerHTML = html;
348
349 if ( options.showDate ) {
350 var dates = relatedPosts.querySelectorAll( '.jp-relatedposts-post-date' );
351
352 Array.prototype.forEach.call( dates, function ( date ) {
353 date.style.display = 'block';
354 } );
355 }
356
357 relatedPosts.style.display = 'block';
358 afterPostsHaveLoaded();
359 } catch ( error ) {
360 // Do nothing
361 }
362 }
363 };
364
365 request.send();
366 }
367
368 function init() {
369 if ( 'undefined' !== typeof wp && wp.customize ) {
370 if ( wp.customize.selectiveRefresh ) {
371 wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function ( placement ) {
372 if ( 'jetpack_relatedposts' === placement.partial.id ) {
373 startRelatedPosts();
374 }
375 } );
376 }
377 wp.customize.bind( 'preview-ready', startRelatedPosts );
378 } else {
379 startRelatedPosts();
380 }
381 }
382
383 if ( document.readyState !== 'loading' ) {
384 init();
385 } else {
386 document.addEventListener( 'DOMContentLoaded', init );
387 }
388 } )();
389