PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.2.4
Jetpack – WP Security, Backup, Speed, & Growth v13.2.4
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 2 years ago jetpack-related-posts.php 2 years ago readme.md 3 years ago related-posts-customizer.js 6 years ago related-posts-rtl.css 2 years ago related-posts.css 2 years ago related-posts.js 3 years ago
related-posts.js
391 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 ( post.img.srcset ? '" srcset="' + post.img.srcset : '' ) +
175 ( post.img.sizes ? '" sizes="' + post.img.sizes : '' ) +
176 '" alt="' +
177 post.img.alt_text +
178 '" />' +
179 anchor[ 1 ];
180 } else {
181 var anchor_overlay = self.getAnchor(
182 post,
183 'jp-relatedposts-post-a jp-relatedposts-post-aoverlay'
184 );
185 html += anchor_overlay[ 0 ] + anchor_overlay[ 1 ];
186 }
187 html +=
188 '<' +
189 related_posts_js_options.post_heading +
190 ' class="jp-relatedposts-post-title">' +
191 anchor[ 0 ] +
192 post.title +
193 anchor[ 1 ] +
194 '</' +
195 related_posts_js_options.post_heading +
196 '>';
197 html += '<p class="jp-relatedposts-post-excerpt">' + excerpt + '</p>';
198 if ( options.showDate ) {
199 html +=
200 '<time class="jp-relatedposts-post-date" datetime="' +
201 post.date +
202 '">' +
203 post.date +
204 '</time>';
205 }
206 if ( options.showContext ) {
207 html += '<p class="jp-relatedposts-post-context">' + post.context + '</p>';
208 }
209 html += '</div>';
210 } );
211 return (
212 '<div class="jp-relatedposts-items jp-relatedposts-items-visual jp-relatedposts-' +
213 options.layout +
214 ' ">' +
215 html +
216 '</div>'
217 );
218 },
219
220 /**
221 * We want to set a max height on the excerpt however we want to set
222 * this according to the natual pacing of the page as we never want to
223 * cut off a line of text in the middle so we need to do some detective
224 * work.
225 */
226 setVisualExcerptHeights: function () {
227 var elements = document.querySelectorAll(
228 '#jp-relatedposts .jp-relatedposts-post-nothumbs .jp-relatedposts-post-excerpt'
229 );
230
231 if ( ! elements.length ) {
232 return;
233 }
234
235 var firstElementStyles = getComputedStyle( elements[ 0 ] );
236
237 var fontSize = parseInt( firstElementStyles.fontSize, 10 );
238 var lineHeight = parseInt( firstElementStyles.lineHeight, 10 );
239
240 // Show 5 lines of text
241 for ( var i = 0; i < elements.length; i++ ) {
242 elements[ i ].style.maxHeight = ( 5 * lineHeight ) / fontSize + 'em';
243 }
244 },
245
246 getTrackedUrl: function ( anchor ) {
247 var args = 'relatedposts_hit=1';
248 args += '&relatedposts_origin=' + anchor.getAttribute( 'data-origin' );
249 args += '&relatedposts_position=' + anchor.getAttribute( 'data-position' );
250
251 var pathname = anchor.pathname;
252 if ( '/' !== pathname[ 0 ] ) {
253 pathname = '/' + pathname;
254 }
255
256 if ( '' === anchor.search ) {
257 return pathname + '?' + args;
258 } else {
259 return pathname + anchor.search + '&' + args;
260 }
261 },
262
263 cleanupTrackedUrl: function () {
264 if ( 'function' !== typeof history.replaceState ) {
265 return;
266 }
267
268 var cleaned_search = document.location.search.replace(
269 /\brelatedposts_[a-z]+=[0-9]*&?\b/gi,
270 ''
271 );
272 if ( '?' === cleaned_search ) {
273 cleaned_search = '';
274 }
275 if ( document.location.search !== cleaned_search ) {
276 history.replaceState( {}, document.title, document.location.pathname + cleaned_search );
277 }
278 },
279 };
280
281 function afterPostsHaveLoaded() {
282 jprp.setVisualExcerptHeights();
283 var posts = document.querySelectorAll( '#jp-relatedposts a.jp-relatedposts-post-a' );
284
285 Array.prototype.forEach.call( posts, function ( post ) {
286 document.addEventListener( 'click', function () {
287 post.href = jprp.getTrackedUrl( post );
288 } );
289 } );
290 }
291
292 /**
293 * Initialize Related Posts.
294 */
295 function startRelatedPosts() {
296 jprp.cleanupTrackedUrl();
297
298 var endpointURL = jprp.getEndpointURL();
299 var relatedPosts = document.querySelector( '#jp-relatedposts' );
300
301 if ( ! endpointURL ) {
302 return;
303 }
304
305 if ( document.querySelectorAll( '#jp-relatedposts .jp-relatedposts-post' ).length ) {
306 afterPostsHaveLoaded();
307 return;
308 }
309
310 var request = new XMLHttpRequest();
311 request.open( 'GET', endpointURL, true );
312 request.setRequestHeader( 'x-requested-with', 'XMLHttpRequest' );
313
314 request.onreadystatechange = function () {
315 if ( this.readyState === XMLHttpRequest.DONE && this.status === 200 ) {
316 try {
317 var response = JSON.parse( request.responseText );
318
319 if ( 0 === response.items.length || 0 === relatedPosts.length ) {
320 return;
321 }
322
323 jprp.response = response;
324
325 var html,
326 showThumbnails,
327 options = {};
328
329 if ( 'undefined' !== typeof wp && wp.customize ) {
330 showThumbnails = wp.customize.instance( 'jetpack_relatedposts[show_thumbnails]' ).get();
331 options.showDate = wp.customize.instance( 'jetpack_relatedposts[show_date]' ).get();
332 options.showContext = wp.customize
333 .instance( 'jetpack_relatedposts[show_context]' )
334 .get();
335 options.layout = wp.customize.instance( 'jetpack_relatedposts[layout]' ).get();
336 } else {
337 showThumbnails = response.show_thumbnails;
338 options.showDate = response.show_date;
339 options.showContext = response.show_context;
340 options.layout = response.layout;
341 }
342
343 html = ! showThumbnails
344 ? jprp.generateMinimalHtml( response.items, options )
345 : jprp.generateVisualHtml( response.items, options );
346
347 var div = document.createElement( 'div' );
348 relatedPosts.appendChild( div );
349 div.outerHTML = html;
350
351 if ( options.showDate ) {
352 var dates = relatedPosts.querySelectorAll( '.jp-relatedposts-post-date' );
353
354 Array.prototype.forEach.call( dates, function ( date ) {
355 date.style.display = 'block';
356 } );
357 }
358
359 relatedPosts.style.display = 'block';
360 afterPostsHaveLoaded();
361 } catch ( error ) {
362 // Do nothing
363 }
364 }
365 };
366
367 request.send();
368 }
369
370 function init() {
371 if ( 'undefined' !== typeof wp && wp.customize ) {
372 if ( wp.customize.selectiveRefresh ) {
373 wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function ( placement ) {
374 if ( 'jetpack_relatedposts' === placement.partial.id ) {
375 startRelatedPosts();
376 }
377 } );
378 }
379 wp.customize.bind( 'preview-ready', startRelatedPosts );
380 } else {
381 startRelatedPosts();
382 }
383 }
384
385 if ( document.readyState !== 'loading' ) {
386 init();
387 } else {
388 document.addEventListener( 'DOMContentLoaded', init );
389 }
390 } )();
391