Completed
Push — v2/videopress ( 00803f...fad9d3 )
by George
20:00 queued 09:44
created

Jetpack_RelatedPosts::_enqueue_assets()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 23
rs 8.7972
cc 4
eloc 11
nc 6
nop 2
1
<?php
2
class Jetpack_RelatedPosts {
3
	const VERSION = '20150408';
4
	const SHORTCODE = 'jetpack-related-posts';
5
6
	/**
7
	 * Creates and returns a static instance of Jetpack_RelatedPosts.
8
	 *
9
	 * @return Jetpack_RelatedPosts
10
	 */
11 View Code Duplication
	public static function init() {
12
		static $instance = NULL;
13
14
		if ( ! $instance ) {
15
			if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init' ) ) {
16
				$instance = WPCOM_RelatedPosts::init();
17
			} else {
18
				$instance = new Jetpack_RelatedPosts(
19
					get_current_blog_id(),
20
					Jetpack_Options::get_option( 'id' )
21
				);
22
			}
23
		}
24
25
		return $instance;
26
	}
27
28
	/**
29
	 * Creates and returns a static instance of Jetpack_RelatedPosts_Raw.
30
	 *
31
	 * @return Jetpack_RelatedPosts
32
	 */
33 View Code Duplication
	public static function init_raw() {
34
		static $instance = NULL;
35
36
		if ( ! $instance ) {
37
			if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init_raw' ) ) {
38
				$instance = WPCOM_RelatedPosts::init_raw();
39
			} else {
40
				$instance = new Jetpack_RelatedPosts_Raw(
41
					get_current_blog_id(),
42
					Jetpack_Options::get_option( 'id' )
43
				);
44
			}
45
		}
46
47
		return $instance;
48
	}
49
50
	protected $_blog_id_local;
51
	protected $_blog_id_wpcom;
52
	protected $_options;
53
	protected $_allow_feature_toggle;
54
	protected $_blog_charset;
55
	protected $_convert_charset;
56
	protected $_previous_post_id;
57
	protected $_found_shortcode = false;
58
59
	/**
60
	 * Constructor for Jetpack_RelatedPosts.
61
	 *
62
	 * @param int $blog_id_local
63
	 * @param int $blog_id_wpcom
64
	 * @uses get_option, add_action, apply_filters
65
	 * @return null
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
66
	 */
67
	public function __construct( $blog_id_local, $blog_id_wpcom ) {
68
		$this->_blog_id_local = $blog_id_local;
69
		$this->_blog_id_wpcom = $blog_id_wpcom;
70
		$this->_blog_charset = get_option( 'blog_charset' );
71
		$this->_convert_charset = ( function_exists( 'iconv' ) && ! preg_match( '/^utf\-?8$/i', $this->_blog_charset ) );
72
73
		add_action( 'admin_init', array( $this, 'action_admin_init' ) );
74
		add_action( 'wp', array( $this, 'action_frontend_init' ) );
75
	}
76
77
	/**
78
	 * =================
79
	 * ACTIONS & FILTERS
80
	 * =================
81
	 */
82
83
	/**
84
	 * Add a checkbox field to Settings > Reading for enabling related posts.
85
	 *
86
	 * @action admin_init
87
	 * @uses add_settings_field, __, register_setting, add_action
88
	 * @return null
89
	 */
90
	public function action_admin_init() {
91
92
		// Add the setting field [jetpack_relatedposts] and place it in Settings > Reading
93
		add_settings_field( 'jetpack_relatedposts', '<span id="jetpack_relatedposts">' . __( 'Related posts', 'jetpack' ) . '</span>', array( $this, 'print_setting_html' ), 'reading' );
94
		register_setting( 'reading', 'jetpack_relatedposts', array( $this, 'parse_options' ) );
95
		add_action('admin_head', array( $this, 'print_setting_head' ) );
96
97
		if( 'options-reading.php' == $GLOBALS['pagenow'] ) {
98
			// Enqueue style for live preview on the reading settings page
99
			$this->_enqueue_assets( false, true );
100
		}
101
	}
102
103
	/**
104
	 * Load related posts assets if it's a elegiable frontend page or execute search and return JSON if it's an endpoint request.
105
	 *
106
	 * @global $_GET
107
	 * @action wp
108
	 * @uses add_shortcode, get_the_ID
109
	 * @returns null
110
	 */
111
	public function action_frontend_init() {
112
		// Add a shortcode handler that outputs nothing, this gets overridden later if we can display related content
113
		add_shortcode( self::SHORTCODE, array( $this, 'get_target_html_unsupported' ) );
114
115
		if ( ! $this->_enabled_for_request() )
116
			return;
117
118
		if ( isset( $_GET['relatedposts'] ) ) {
119
			$excludes = array();
120
			if ( isset( $_GET['relatedposts_exclude'] ) ) {
121
				$excludes = explode( ',', $_GET['relatedposts_exclude'] );
122
			}
123
124
			$this->_action_frontend_init_ajax( $excludes );
125
		} else {
126
			if ( isset( $_GET['relatedposts_hit'] ) ) {
127
				$this->_log_click( $_GET['relatedposts_origin'], get_the_ID(), $_GET['relatedposts_position'] );
128
				$this->_previous_post_id = (int) $_GET['relatedposts_origin'];
129
			}
130
131
			$this->_action_frontend_init_page();
132
		}
133
134
	}
135
136
	/**
137
	 * Adds a target to the post content to load related posts into if a shortcode for it did not already exist.
138
	 *
139
	 * @filter the_content
140
	 * @param string $content
141
	 * @returns string
142
	 */
143
	public function filter_add_target_to_dom( $content ) {
144
		if ( !$this->_found_shortcode ) {
145
			$content .= "\n" . $this->get_target_html();
146
		}
147
148
		return $content;
149
	}
150
151
	/**
152
	 * Looks for our shortcode on the unfiltered content, this has to execute early.
153
	 *
154
	 * @filter the_content
155
	 * @param string $content
156
	 * @uses has_shortcode
157
	 * @returns string
158
	 */
159
	public function test_for_shortcode( $content ) {
160
		$this->_found_shortcode = has_shortcode( $content, self::SHORTCODE );
161
162
		return $content;
163
	}
164
165
	/**
166
	 * Returns the HTML for the related posts section.
167
	 *
168
	 * @uses esc_html__, apply_filters
169
	 * @returns string
170
	 */
171
	public function get_target_html() {
172
		$options = $this->get_options();
173
174
		if ( $options['show_headline'] ) {
175
			$headline = sprintf(
176
				'<h3 class="jp-relatedposts-headline"><em>%s</em></h3>',
177
				esc_html__( 'Related', 'jetpack' )
178
			);
179
		} else {
180
			$headline = '';
181
		}
182
183
		/**
184
		 * Filter the Related Posts headline.
185
		 *
186
		 * @module related-posts
187
		 *
188
		 * @since 3.0.0
189
		 *
190
		 * @param string $headline Related Posts heading.
191
		 */
192
		$headline = apply_filters( 'jetpack_relatedposts_filter_headline', $headline );
193
194
		if ( $this->_previous_post_id ) {
195
			$exclude = "data-exclude='{$this->_previous_post_id}'";
196
		} else {
197
			$exclude = "";
198
		}
199
200
		return <<<EOT
201
<div id='jp-relatedposts' class='jp-relatedposts' $exclude>
202
	$headline
203
</div>
204
EOT;
205
	}
206
207
	/**
208
	 * Returns the HTML for the related posts section if it's running in the loop or other instances where we don't support related posts.
209
	 *
210
	 * @returns string
211
	 */
212
	public function get_target_html_unsupported() {
213
		return "\n\n<!-- Jetpack Related Posts is not supported in this context. -->\n\n";
214
	}
215
216
	/**
217
	 * ========================
218
	 * PUBLIC UTILITY FUNCTIONS
219
	 * ========================
220
	 */
221
222
	/**
223
	 * Gets options set for Jetpack_RelatedPosts and merge with defaults.
224
	 *
225
	 * @uses Jetpack_Options::get_option, apply_filters
226
	 * @return array
227
	 */
228
	public function get_options() {
229
		if ( null === $this->_options ) {
230
			$this->_options = Jetpack_Options::get_option( 'relatedposts' );
231
			if ( ! is_array( $this->_options ) )
232
				$this->_options = array();
233
			if ( ! isset( $this->_options['enabled'] ) )
234
				$this->_options['enabled'] = true;
235
			if ( ! isset( $this->_options['show_headline'] ) )
236
				$this->_options['show_headline'] = true;
237
			if ( ! isset( $this->_options['show_thumbnails'] ) )
238
				$this->_options['show_thumbnails'] = false;
239
			if ( empty( $this->_options['size'] ) || (int)$this->_options['size'] < 1 )
240
				$this->_options['size'] = 3;
241
242
			/**
243
			 * Filter Related Posts basic options.
244
			 *
245
			 * @module related-posts
246
			 *
247
			 * @since 2.8.0
248
			 *
249
			 * @param array $this->_options Array of basic Related Posts options.
250
			 */
251
			$this->_options = apply_filters( 'jetpack_relatedposts_filter_options', $this->_options );
252
		}
253
254
		return $this->_options;
255
	}
256
257
	/**
258
	 * Parses input and returnes normalized options array.
259
	 *
260
	 * @param array $input
261
	 * @uses self::get_options
262
	 * @return array
263
	 */
264
	public function parse_options( $input ) {
265
		$current = $this->get_options();
266
267
		if ( !is_array( $input ) )
268
			$input = array();
269
270
		if ( isset( $input['enabled'] ) && '1' == $input['enabled'] ) {
271
			$current['enabled'] = true;
272
			$current['show_headline'] = ( isset( $input['show_headline'] ) && '1' == $input['show_headline'] );
273
			$current['show_thumbnails'] = ( isset( $input['show_thumbnails'] ) && '1' == $input['show_thumbnails'] );
274
		} else {
275
			$current['enabled'] = false;
276
		}
277
278
		if ( isset( $input['size'] ) && (int)$input['size'] > 0 )
279
			$current['size'] = (int)$input['size'];
280
		else
281
			$current['size'] = null;
282
283
		return $current;
284
	}
285
286
	/**
287
	 * HTML for admin settings page.
288
	 *
289
	 * @uses self::get_options, checked, esc_html__
290
	 * @returns null
291
	 */
292
	public function print_setting_html() {
293
		$options = $this->get_options();
294
295
		$ui_settings_template = <<<EOT
296
<ul id="settings-reading-relatedposts-customize">
297
	<li>
298
		<label><input name="jetpack_relatedposts[show_headline]" type="checkbox" value="1" %s /> %s</label>
299
	</li>
300
	<li>
301
		<label><input name="jetpack_relatedposts[show_thumbnails]" type="checkbox" value="1" %s /> %s</label>
302
	</li>
303
</ul>
304
<div id='settings-reading-relatedposts-preview'>
305
	%s
306
	<div id="jp-relatedposts" class="jp-relatedposts"></div>
307
</div>
308
EOT;
309
		$ui_settings = sprintf(
310
			$ui_settings_template,
311
			checked( $options['show_headline'], true, false ),
312
			esc_html__( 'Show a "Related" header to more clearly separate the related section from posts', 'jetpack' ),
313
			checked( $options['show_thumbnails'], true, false ),
314
			esc_html__( 'Use a large and visually striking layout', 'jetpack' ),
315
			esc_html__( 'Preview:', 'jetpack' )
316
		);
317
318
		if ( !$this->_allow_feature_toggle() ) {
319
			$template = <<<EOT
320
<input type="hidden" name="jetpack_relatedposts[enabled]" value="1" />
321
%s
322
EOT;
323
			printf(
324
				$template,
325
				$ui_settings
326
			);
327
		} else {
328
			$template = <<<EOT
329
<ul id="settings-reading-relatedposts">
330
	<li>
331
		<label><input type="radio" name="jetpack_relatedposts[enabled]" value="0" class="tog" %s /> %s</label>
332
	</li>
333
	<li>
334
		<label><input type="radio" name="jetpack_relatedposts[enabled]" value="1" class="tog" %s /> %s</label>
335
		%s
336
	</li>
337
</ul>
338
EOT;
339
			printf(
340
				$template,
341
				checked( $options['enabled'], false, false ),
342
				esc_html__( 'Hide related content after posts', 'jetpack' ),
343
				checked( $options['enabled'], true, false ),
344
				esc_html__( 'Show related content after posts', 'jetpack' ),
345
				$ui_settings
346
			);
347
		}
348
	}
349
350
	/**
351
	 * Head JS/CSS for admin settings page.
352
	 *
353
	 * @uses esc_html__
354
	 * @returns null
355
	 */
356
	public function print_setting_head() {
357
358
		// only dislay the Related Posts JavaScript on the Reading Settings Admin Page
359
		$current_screen =  get_current_screen();
360
		if( 'options-reading' != $current_screen->id )
361
			return;
362
363
		$related_headline = sprintf(
364
			'<h3 class="jp-relatedposts-headline"><em>%s</em></h3>',
365
			esc_html__( 'Related', 'jetpack' )
366
		);
367
368
		$href_params = 'class="jp-relatedposts-post-a" href="#jetpack_relatedposts" rel="nofollow" data-origin="0" data-position="0"';
369
		$related_with_images = <<<EOT
370
<div class="jp-relatedposts-items jp-relatedposts-items-visual">
371
	<div class="jp-relatedposts-post jp-relatedposts-post0 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
372
		<a $href_params>
373
			<img class="jp-relatedposts-post-img" src="http://jetpackme.files.wordpress.com/2014/08/1-wpios-ipad-3-1-viewsite.png?w=350&amp;h=200&amp;crop=1" width="350" alt="Big iPhone/iPad Update Now Available" scale="0">
374
		</a>
375
		<h4 class="jp-relatedposts-post-title">
376
			<a $href_params>Big iPhone/iPad Update Now Available</a>
377
		</h4>
378
		<p class="jp-relatedposts-post-excerpt">Big iPhone/iPad Update Now Available</p>
379
		<p class="jp-relatedposts-post-context">In "Mobile"</p>
380
	</div>
381
	<div class="jp-relatedposts-post jp-relatedposts-post1 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
382
		<a $href_params>
383
			<img class="jp-relatedposts-post-img" src="http://jetpackme.files.wordpress.com/2014/08/wordpress-com-news-wordpress-for-android-ui-update2.jpg?w=350&amp;h=200&amp;crop=1" width="350" alt="The WordPress for Android App Gets a Big Facelift" scale="0">
384
		</a>
385
		<h4 class="jp-relatedposts-post-title">
386
			<a $href_params>The WordPress for Android App Gets a Big Facelift</a>
387
		</h4>
388
		<p class="jp-relatedposts-post-excerpt">The WordPress for Android App Gets a Big Facelift</p>
389
		<p class="jp-relatedposts-post-context">In "Mobile"</p>
390
	</div>
391
	<div class="jp-relatedposts-post jp-relatedposts-post2 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
392
		<a $href_params>
393
			<img class="jp-relatedposts-post-img" src="http://jetpackme.files.wordpress.com/2014/08/videopresswedding.jpg?w=350&amp;h=200&amp;crop=1" width="350" alt="Upgrade Focus: VideoPress For Weddings" scale="0">
394
		</a>
395
		<h4 class="jp-relatedposts-post-title">
396
			<a $href_params>Upgrade Focus: VideoPress For Weddings</a>
397
		</h4>
398
		<p class="jp-relatedposts-post-excerpt">Upgrade Focus: VideoPress For Weddings</p>
399
		<p class="jp-relatedposts-post-context">In "Upgrade"</p>
400
	</div>
401
</div>
402
EOT;
403
		$related_with_images = str_replace( "\n", '', $related_with_images );
404
		$related_without_images = <<<EOT
405
<div class="jp-relatedposts-items jp-relatedposts-items-minimal">
406
	<p class="jp-relatedposts-post jp-relatedposts-post0" data-post-id="0" data-post-format="image">
407
		<span class="jp-relatedposts-post-title"><a $href_params>Big iPhone/iPad Update Now Available</a></span>
408
		<span class="jp-relatedposts-post-context">In "Mobile"</span>
409
	</p>
410
	<p class="jp-relatedposts-post jp-relatedposts-post1" data-post-id="0" data-post-format="image">
411
		<span class="jp-relatedposts-post-title"><a $href_params>The WordPress for Android App Gets a Big Facelift</a></span>
412
		<span class="jp-relatedposts-post-context">In "Mobile"</span>
413
	</p>
414
	<p class="jp-relatedposts-post jp-relatedposts-post2" data-post-id="0" data-post-format="image">
415
		<span class="jp-relatedposts-post-title"><a $href_params>Upgrade Focus: VideoPress For Weddings</a></span>
416
		<span class="jp-relatedposts-post-context">In "Upgrade"</span>
417
	</p>
418
</div>
419
EOT;
420
		$related_without_images = str_replace( "\n", '', $related_without_images );
421
422
		if ( $this->_allow_feature_toggle() ) {
423
			$extra_css = '#settings-reading-relatedposts-customize { padding-left:2em; margin-top:.5em; }';
424
		} else {
425
			$extra_css = '';
426
		}
427
428
		echo <<<EOT
429
<style type="text/css">
430
	#settings-reading-relatedposts .disabled { opacity:.5; filter:Alpha(opacity=50); }
431
	#settings-reading-relatedposts-preview .jp-relatedposts { background:#fff; padding:.5em; width:75%; }
432
	$extra_css
433
</style>
434
<script type="text/javascript">
435
	jQuery( document ).ready( function($) {
436
		var update_ui = function() {
437
			var is_enabled = true;
438
			if ( 'radio' == $( 'input[name="jetpack_relatedposts[enabled]"]' ).attr('type') ) {
439
				if ( '0' == $( 'input[name="jetpack_relatedposts[enabled]"]:checked' ).val() ) {
440
					is_enabled = false;
441
				}
442
			}
443
			if ( is_enabled ) {
444
				$( '#settings-reading-relatedposts-customize' )
445
					.removeClass( 'disabled' )
446
					.find( 'input' )
447
					.attr( 'disabled', false );
448
				$( '#settings-reading-relatedposts-preview' )
449
					.removeClass( 'disabled' );
450
			} else {
451
				$( '#settings-reading-relatedposts-customize' )
452
					.addClass( 'disabled' )
453
					.find( 'input' )
454
					.attr( 'disabled', true );
455
				$( '#settings-reading-relatedposts-preview' )
456
					.addClass( 'disabled' );
457
			}
458
		};
459
460
		var update_preview = function() {
461
			var html = '';
462
			if ( $( 'input[name="jetpack_relatedposts[show_headline]"]:checked' ).size() ) {
463
				html += '$related_headline';
464
			}
465
			if ( $( 'input[name="jetpack_relatedposts[show_thumbnails]"]:checked' ).size() ) {
466
				html += '$related_with_images';
467
			} else {
468
				html += '$related_without_images';
469
			}
470
			$( '#settings-reading-relatedposts-preview .jp-relatedposts' )
471
				.html( html )
472
				.show();
473
		};
474
475
		// Update on load
476
		update_preview();
477
		update_ui();
478
479
		// Update on change
480
		$( '#settings-reading-relatedposts-customize input' )
481
			.change( update_preview );
482
		$( '#settings-reading-relatedposts' )
483
			.find( 'input.tog' )
484
			.change( update_ui );
485
	});
486
</script>
487
EOT;
488
	}
489
490
	/**
491
	 * Gets an array of related posts that match the given post_id.
492
	 *
493
	 * @param int $post_id
494
	 * @param array $args - params to use when building ElasticSearch filters to narrow down the search domain.
495
	 * @uses self::get_options, get_post_type, wp_parse_args, apply_filters
496
	 * @return array
497
	 */
498
	public function get_for_post_id( $post_id, array $args ) {
499
		$options = $this->get_options();
500
501
		if ( ! empty( $args['size'] ) )
502
			$options['size'] = $args['size'];
503
504
		if ( ! $options['enabled'] || 0 == (int)$post_id || empty( $options['size'] ) )
505
			return array();
506
507
		$defaults = array(
508
			'size' => (int)$options['size'],
509
			'post_type' => get_post_type( $post_id ),
510
			'post_formats' => array(),
511
			'has_terms' => array(),
512
			'date_range' => array(),
513
			'exclude_post_ids' => array(),
514
		);
515
		$args = wp_parse_args( $args, $defaults );
516
		/**
517
		 * Filter the arguments used to retrieve a list of Related Posts.
518
		 *
519
		 * @module related-posts
520
		 *
521
		 * @since 2.8.0
522
		 *
523
		 * @param array $args Array of options to retrieve Related Posts.
524
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
525
		 */
526
		$args = apply_filters( 'jetpack_relatedposts_filter_args', $args, $post_id );
527
528
		$filters = $this->_get_es_filters_from_args( $post_id, $args );
529
		/**
530
		 * Filter ElasticSearch options used to calculate Related Posts.
531
		 *
532
		 * @module related-posts
533
		 *
534
		 * @since 2.8.0
535
		 *
536
		 * @param array $filters Array of ElasticSearch filters based on the post_id and args.
537
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
538
		 */
539
		$filters = apply_filters( 'jetpack_relatedposts_filter_filters', $filters, $post_id );
540
541
		$results = $this->_get_related_posts( $post_id, $args['size'], $filters );
542
		/**
543
		 * Filter the array of related posts matched by ElasticSearch.
544
		 *
545
		 * @module related-posts
546
		 *
547
		 * @since 2.8.0
548
		 *
549
		 * @param array $results Array of related posts matched by ElasticSearch.
550
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
551
		 */
552
		return apply_filters( 'jetpack_relatedposts_returned_results', $results, $post_id );
553
	}
554
555
	/**
556
	 * =========================
557
	 * PRIVATE UTILITY FUNCTIONS
558
	 * =========================
559
	 */
560
561
	/**
562
	 * Creates an array of ElasticSearch filters based on the post_id and args.
563
	 *
564
	 * @param int $post_id
565
	 * @param array $args
566
	 * @uses apply_filters, get_post_types, get_post_format_strings
567
	 * @return array
568
	 */
569
	protected function _get_es_filters_from_args( $post_id, array $args ) {
570
		$filters = array();
571
572
		/**
573
		 * Filter the terms used to search for Related Posts.
574
		 *
575
		 * @module related-posts
576
		 *
577
		 * @since 2.8.0
578
		 *
579
		 * @param array $args['has_terms'] Array of terms associated to the Related Posts.
580
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
581
		 */
582
		$args['has_terms'] = apply_filters( 'jetpack_relatedposts_filter_has_terms', $args['has_terms'], $post_id );
583
		if ( ! empty( $args['has_terms'] ) ) {
584
			foreach( (array)$args['has_terms'] as $term ) {
585
				if ( mb_strlen( $term->taxonomy ) ) {
586
					switch ( $term->taxonomy ) {
587
						case 'post_tag':
588
							$tax_fld = 'tag.slug';
589
							break;
590
						case 'category':
591
							$tax_fld = 'category.slug';
592
							break;
593
						default:
594
							$tax_fld = 'taxonomy.' . $term->taxonomy . '.slug';
595
							break;
596
					}
597
					$filters[] = array( 'term' => array( $tax_fld => $term->slug ) );
598
				}
599
			}
600
		}
601
602
		/**
603
		 * Filter the Post Types where we search Related Posts.
604
		 *
605
		 * @module related-posts
606
		 *
607
		 * @since 2.8.0
608
		 *
609
		 * @param array $args['post_type'] Array of Post Types.
610
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
611
		 */
612
		$args['post_type'] = apply_filters( 'jetpack_relatedposts_filter_post_type', $args['post_type'], $post_id );
613
		$valid_post_types = get_post_types();
614
		if ( is_array( $args['post_type'] ) ) {
615
			$sanitized_post_types = array();
616
			foreach ( $args['post_type'] as $pt ) {
617
				if ( in_array( $pt, $valid_post_types ) )
618
					$sanitized_post_types[] = $pt;
619
			}
620
			if ( ! empty( $sanitized_post_types ) )
621
				$filters[] = array( 'terms' => array( 'post_type' => $sanitized_post_types ) );
622
		} else if ( in_array( $args['post_type'], $valid_post_types ) && 'all' != $args['post_type'] ) {
623
			$filters[] = array( 'term' => array( 'post_type' => $args['post_type'] ) );
624
		}
625
626
		/**
627
		 * Filter the Post Formats where we search Related Posts.
628
		 *
629
		 * @module related-posts
630
		 *
631
		 * @since 3.3.0
632
		 *
633
		 * @param array $args['post_formats'] Array of Post Formats.
634
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
635
		 */
636
		$args['post_formats'] = apply_filters( 'jetpack_relatedposts_filter_post_formats', $args['post_formats'], $post_id );
637
		$valid_post_formats = get_post_format_strings();
638
		$sanitized_post_formats = array();
639
		foreach ( $args['post_formats'] as $pf ) {
640
			if ( array_key_exists( $pf, $valid_post_formats ) ) {
641
				$sanitized_post_formats[] = $pf;
642
			}
643
		}
644
		if ( ! empty( $sanitized_post_formats ) ) {
645
			$filters[] = array( 'terms' => array( 'post_format' => $sanitized_post_formats ) );
646
		}
647
648
		/**
649
		 * Filter the date range used to search Related Posts.
650
		 *
651
		 * @module related-posts
652
		 *
653
		 * @since 2.8.0
654
		 *
655
		 * @param array $args['date_range'] Array of a month interval where we search Related Posts.
656
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
657
		 */
658
		$args['date_range'] = apply_filters( 'jetpack_relatedposts_filter_date_range', $args['date_range'], $post_id );
659
		if ( is_array( $args['date_range'] ) && ! empty( $args['date_range'] ) ) {
660
			$args['date_range'] = array_map( 'intval', $args['date_range'] );
661
			if ( !empty( $args['date_range']['from'] ) && !empty( $args['date_range']['to'] ) ) {
662
				$filters[] = array(
663
					'range' => array(
664
						'date_gmt' => $this->_get_coalesced_range( $args['date_range'] ),
665
					)
666
				);
667
			}
668
		}
669
670
		/**
671
		 * Filter the Post IDs excluded from appearing in Related Posts.
672
		 *
673
		 * @module related-posts
674
		 *
675
		 * @since 2.9.0
676
		 *
677
		 * @param array $args['exclude_post_ids'] Array of Post IDs.
678
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
679
		 */
680
		$args['exclude_post_ids'] = apply_filters( 'jetpack_relatedposts_filter_exclude_post_ids', $args['exclude_post_ids'], $post_id );
681
		if ( !empty( $args['exclude_post_ids'] ) && is_array( $args['exclude_post_ids'] ) ) {
682
			foreach ( $args['exclude_post_ids'] as $exclude_post_id) {
683
				$exclude_post_id = (int)$exclude_post_id;
684
685
				if ( $exclude_post_id > 0 )
686
					$filters[] = array( 'not' => array( 'term' => array( 'post_id' => $exclude_post_id ) ) );
687
			}
688
		}
689
690
		return $filters;
691
	}
692
693
	/**
694
	 * Takes a range and coalesces it into a month interval bracketed by a time as determined by the blog_id to enhance caching.
695
	 *
696
	 * @param array $date_range
697
	 * @return array
698
	 */
699
	protected function _get_coalesced_range( array $date_range ) {
700
		$now = time();
701
		$coalesce_time = $this->_blog_id_wpcom % 86400;
702
		$current_time = $now - strtotime( 'today', $now );
703
704
		if ( $current_time < $coalesce_time && '01' == date( 'd', $now ) ) {
705
			// Move back 1 period
706
			return array(
707
				'from' => date( 'Y-m-01', strtotime( '-1 month', $date_range['from'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
708
				'to'   => date( 'Y-m-01', $date_range['to'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
709
			);
710
		} else {
711
			// Use current period
712
			return array(
713
				'from' => date( 'Y-m-01', $date_range['from'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
714
				'to'   => date( 'Y-m-01', strtotime( '+1 month', $date_range['to'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
715
			);
716
		}
717
	}
718
719
	/**
720
	 * Generate and output ajax response for related posts API call.
721
	 * NOTE: Calls exit() to end all further processing after payload has been outputed.
722
	 *
723
	 * @param array $excludes array of post_ids to exclude
724
	 * @uses send_nosniff_header, self::get_for_post_id, get_the_ID
725
	 * @return null
726
	 */
727
	protected function _action_frontend_init_ajax( array $excludes ) {
728
		define( 'DOING_AJAX', true );
729
730
		header( 'Content-type: application/json; charset=utf-8' ); // JSON can only be UTF-8
731
		send_nosniff_header();
732
733
		$related_posts = $this->get_for_post_id(
734
			get_the_ID(),
735
			array(
736
				'exclude_post_ids' => $excludes,
737
			)
738
		);
739
740
		$options = $this->get_options();
741
742
		$response = array(
743
			'version' => self::VERSION,
744
			'show_thumbnails' => (bool) $options['show_thumbnails'],
745
			'items' => array(),
746
		);
747
748
		if ( count( $related_posts ) == $options['size'] )
749
			$response['items'] = $related_posts;
750
751
		echo json_encode( $response );
752
753
		exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method _action_frontend_init_ajax() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
754
	}
755
756
	/**
757
	 * Returns a UTF-8 encoded array of post information for the given post_id
758
	 *
759
	 * @param int $post_id
760
	 * @param int $position
761
	 * @param int $origin The post id that this is related to
762
	 * @uses get_post, get_permalink, remove_query_arg, get_post_format, apply_filters
763
	 * @return array
764
	 */
765
	protected function _get_related_post_data_for_post( $post_id, $position, $origin ) {
766
		$post = get_post( $post_id );
767
768
		return array(
769
			'id' => $post->ID,
770
			'url' => get_permalink( $post->ID ),
771
			'url_meta' => array( 'origin' => $origin, 'position' => $position ),
772
			'title' => $this->_to_utf8( $this->_get_title( $post->post_title, $post->post_content ) ),
773
			'date' => get_the_date( '', $post->ID ),
774
			'format' => get_post_format( $post->ID ),
775
			'excerpt' => html_entity_decode( $this->_to_utf8( $this->_get_excerpt( $post->post_excerpt, $post->post_content ) ), ENT_QUOTES, 'UTF-8' ),
776
			/**
777
			 * Filters the rel attribute for the Related Posts' links.
778
			 *
779
			 * @module related-posts
780
			 *
781
			 * @since 3.7.0
782
			 *
783
			 * @param string nofollow Link rel attribute for Related Posts' link. Default is nofollow.
784
			 * @param int $post->ID Post ID.
785
			 */
786
			'rel' => apply_filters( 'jetpack_relatedposts_filter_post_link_rel', 'nofollow', $post->ID ),
787
			/**
788
			 * Filter the context displayed below each Related Post.
789
			 *
790
			 * @module related-posts
791
			 *
792
			 * @since 3.0.0
793
			 *
794
			 * @param string $this->_to_utf8( $this->_generate_related_post_context( $post->ID ) ) Context displayed below each related post.
795
			 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
796
			 */
797
			'context' => apply_filters(
798
				'jetpack_relatedposts_filter_post_context',
799
				$this->_to_utf8( $this->_generate_related_post_context( $post->ID ) ),
800
				$post->ID
801
			),
802
			'img' => $this->_generate_related_post_image_params( $post->ID ),
803
			/**
804
			 * Filter the post css classes added on HTML markup.
805
			 *
806
			 * @module related-posts
807
			 *
808
			 * @since 3.8.0
809
			 *
810
			 * @param array array() CSS classes added on post HTML markup.
811
			 * @param string $post_id Post ID.
812
			 */
813
			'classes' => apply_filters(
814
				'jetpack_relatedposts_filter_post_css_classes',
815
				array(),
816
				$post->ID
817
			),
818
		);
819
	}
820
821
	/**
822
	 * Returns either the title or a small excerpt to use as title for post.
823
	 *
824
	 * @param string $post_title
825
	 * @param string $post_content
826
	 * @uses strip_shortcodes, wp_trim_words, __
827
	 * @return string
828
	 */
829
	protected function _get_title( $post_title, $post_content ) {
830
		if ( ! empty( $post_title ) ) {
831
			return wp_strip_all_tags( $post_title );
832
		}
833
834
		$post_title = wp_trim_words( wp_strip_all_tags( strip_shortcodes( $post_content ) ), 5, '…' );
835
		if ( ! empty( $post_title ) ) {
836
			return $post_title;
837
		}
838
839
		return __( 'Untitled Post', 'jetpack' );
840
	}
841
842
	/**
843
	 * Returns a plain text post excerpt for title attribute of links.
844
	 *
845
	 * @param string $post_excerpt
846
	 * @param string $post_content
847
	 * @uses strip_shortcodes, wp_strip_all_tags, wp_trim_words
848
	 * @return string
849
	 */
850
	protected function _get_excerpt( $post_excerpt, $post_content ) {
851
		if ( empty( $post_excerpt ) )
852
			$excerpt = $post_content;
853
		else
854
			$excerpt = $post_excerpt;
855
856
		return wp_trim_words( wp_strip_all_tags( strip_shortcodes( $excerpt ) ), 50, '…' );
857
	}
858
859
	/**
860
	 * Generates the thumbnail image to be used for the post. Uses the
861
	 * image as returned by Jetpack_PostImages::get_image()
862
	 *
863
	 * @param int $post_id
864
	 * @uses self::get_options, apply_filters, Jetpack_PostImages::get_image, Jetpack_PostImages::fit_image_url
865
	 * @return string
866
	 */
867
	protected function _generate_related_post_image_params( $post_id ) {
868
		$options = $this->get_options();
869
		$image_params = array(
870
			'src' => '',
871
			'width' => 0,
872
			'height' => 0,
873
		);
874
875
		if ( ! $options['show_thumbnails'] ) {
876
			return $image_params;
877
		}
878
879
		/**
880
		 * Filter the size of the Related Posts images.
881
		 *
882
		 * @module related-posts
883
		 *
884
		 * @since 2.8.0
885
		 *
886
		 * @param array array( 'width' => 350, 'height' => 200 ) Size of the images displayed below each Related Post.
887
		 */
888
		$thumbnail_size = apply_filters(
889
			'jetpack_relatedposts_filter_thumbnail_size',
890
			array( 'width' => 350, 'height' => 200 )
891
		);
892
		if ( !is_array( $thumbnail_size ) ) {
893
			$thumbnail_size = array(
894
				'width' => (int)$thumbnail_size,
895
				'height' => (int)$thumbnail_size
896
			);
897
		}
898
899
		// Try to get post image
900
		if ( class_exists( 'Jetpack_PostImages' ) ) {
901
			$img_url = '';
902
			$post_image = Jetpack_PostImages::get_image(
903
				$post_id,
904
				$thumbnail_size
905
			);
906
907
			if ( is_array($post_image) ) {
908
				$img_url = $post_image['src'];
909
			} elseif ( class_exists( 'Jetpack_Media_Summary' ) ) {
910
				$media = Jetpack_Media_Summary::get( $post_id );
911
912
				if ( is_array($media) && !empty( $media['image'] ) ) {
913
					$img_url = $media['image'];
914
				}
915
			}
916
917
			if ( !empty( $img_url ) ) {
918
				$image_params['width'] = $thumbnail_size['width'];
919
				$image_params['height'] = $thumbnail_size['height'];
920
				$image_params['src'] = Jetpack_PostImages::fit_image_url(
921
					$img_url,
922
					$thumbnail_size['width'],
923
					$thumbnail_size['height']
924
				);
925
			}
926
		}
927
928
		return $image_params;
929
	}
930
931
	/**
932
	 * Returns the string UTF-8 encoded
933
	 *
934
	 * @param string $text
935
	 * @return string
936
	 */
937
	protected function _to_utf8( $text ) {
938
		if ( $this->_convert_charset ) {
939
			return iconv( $this->_blog_charset, 'UTF-8', $text );
940
		} else {
941
			return $text;
942
		}
943
	}
944
945
	/**
946
	 * =============================================
947
	 * PROTECTED UTILITY FUNCTIONS EXTENDED BY WPCOM
948
	 * =============================================
949
	 */
950
951
	/**
952
	 * Workhorse method to return array of related posts matched by ElasticSearch.
953
	 *
954
	 * @param int $post_id
955
	 * @param int $size
956
	 * @param array $filters
957
	 * @uses wp_remote_post, is_wp_error, get_option, wp_remote_retrieve_body, get_post, add_query_arg, remove_query_arg, get_permalink, get_post_format, apply_filters
958
	 * @return array
959
	 */
960
	protected function _get_related_posts( $post_id, $size, array $filters ) {
961
		$hits = $this->_filter_non_public_posts(
962
			$this->_get_related_post_ids(
963
				$post_id,
964
				$size,
965
				$filters
966
			)
967
		);
968
969
		/**
970
		 * Filter the Related Posts matched by ElasticSearch.
971
		 *
972
		 * @module related-posts
973
		 *
974
		 * @since 2.9.0
975
		 *
976
		 * @param array $hits Array of Post IDs matched by ElasticSearch.
977
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
978
		 */
979
		$hits = apply_filters( 'jetpack_relatedposts_filter_hits', $hits, $post_id );
980
981
		$related_posts = array();
982
		foreach ( $hits as $i => $hit ) {
983
			$related_posts[] = $this->_get_related_post_data_for_post( $hit['id'], $i, $post_id );
984
		}
985
		return $related_posts;
986
	}
987
988
	/**
989
	 * Get array of related posts matched by ElasticSearch.
990
	 *
991
	 * @param int $post_id
992
	 * @param int $size
993
	 * @param array $filters
994
	 * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body, get_post_meta, update_post_meta
995
	 * @return array
996
	 */
997
	protected function _get_related_post_ids( $post_id, $size, array $filters ) {
998
		$now_ts = time();
999
		$cache_meta_key = '_jetpack_related_posts_cache';
1000
1001
		$body = array(
1002
			'size' => (int) $size,
1003
		);
1004
1005
		if ( !empty( $filters ) )
1006
			$body['filter'] = array( 'and' => $filters );
1007
1008
		// Load all cached values
1009
		$cache = get_post_meta( $post_id, $cache_meta_key, true );
1010
		if ( empty( $cache ) )
1011
			$cache = array();
1012
1013
		// Build cache key
1014
		$cache_key = md5( serialize( $body ) );
1015
1016
		// Cache is valid! Return cached value.
1017
		if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) && $cache[ $cache_key ][ 'expires' ] > $now_ts ) {
1018
			return $cache[ $cache_key ][ 'payload' ];
1019
		}
1020
1021
		$response = wp_remote_post(
1022
			"https://public-api.wordpress.com/rest/v1/sites/{$this->_blog_id_wpcom}/posts/$post_id/related/",
1023
			array(
1024
				'timeout' => 10,
1025
				'user-agent' => 'jetpack_related_posts',
1026
				'sslverify' => true,
1027
				'body' => $body,
1028
			)
1029
		);
1030
1031
		// Oh no... return nothing don't cache errors.
1032
		if ( is_wp_error( $response ) ) {
1033
			if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) )
1034
				return $cache[ $cache_key ][ 'payload' ]; // return stale
1035
			else
1036
				return array();
1037
		}
1038
1039
		$results = json_decode( wp_remote_retrieve_body( $response ), true );
1040
		$related_posts = array();
1041
		if ( is_array( $results ) && !empty( $results['hits'] ) ) {
1042
			foreach( $results['hits'] as $hit ) {
1043
				$related_posts[] = array(
1044
					'id' => $hit['fields']['post_id'],
1045
				);
1046
			}
1047
		}
1048
1049
		// Copy all valid cache values
1050
		$new_cache = array();
1051
		foreach ( $cache as $k => $v ) {
1052
			if ( is_array( $v ) && $v[ 'expires' ] > $now_ts ) {
1053
				$new_cache[ $k ] = $v;
1054
			}
1055
		}
1056
1057
		// Set new cache value if valid
1058
		if ( ! empty( $related_posts ) ) {
1059
			$new_cache[ $cache_key ] = array(
1060
				'expires' => 12 * HOUR_IN_SECONDS + $now_ts,
1061
				'payload' => $related_posts,
1062
			);
1063
		}
1064
1065
		// Update cache
1066
		update_post_meta( $post_id, $cache_meta_key, $new_cache );
1067
1068
		return $related_posts;
1069
	}
1070
1071
	/**
1072
	 * Filter out any hits that are not public anymore.
1073
	 *
1074
	 * @param array $related_posts
1075
	 * @uses get_post_stati, get_post_status
1076
	 * @return array
1077
	 */
1078
	protected function _filter_non_public_posts( array $related_posts ) {
1079
		$public_stati = get_post_stati( array( 'public' => true ) );
1080
1081
		$filtered = array();
1082
		foreach ( $related_posts as $hit ) {
1083
			if ( in_array( get_post_status( $hit['id'] ), $public_stati ) ) {
1084
				$filtered[] = $hit;
1085
			}
1086
		}
1087
		return $filtered;
1088
	}
1089
1090
	/**
1091
	 * Generates a context for the related content (second line in related post output).
1092
	 * Order of importance:
1093
	 *   - First category (Not 'Uncategorized')
1094
	 *   - First post tag
1095
	 *   - Number of comments
1096
	 *
1097
	 * @param int $post_id
1098
	 * @uses get_the_category, get_the_terms, get_comments_number, number_format_i18n, __, _n
1099
	 * @return string
1100
	 */
1101
	protected function _generate_related_post_context( $post_id ) {
1102
		$categories = get_the_category( $post_id );
1103 View Code Duplication
		if ( is_array( $categories ) ) {
1104
			foreach ( $categories as $category ) {
1105
				if ( 'uncategorized' != $category->slug && '' != trim( $category->name ) ) {
1106
					$post_cat_context = sprintf(
1107
						_x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
1108
						$category->name
1109
					);
1110
					/**
1111
					 * Filter the "In Category" line displayed in the post context below each Related Post.
1112
					 *
1113
					 * @module related-posts
1114
					 *
1115
					 * @since 3.2.0
1116
					 *
1117
					 * @param string $post_cat_context "In Category" line displayed in the post context below each Related Post.
1118
					 * @param array $category Array containing information about the category.
1119
					 */
1120
					return apply_filters( 'jetpack_relatedposts_post_category_context', $post_cat_context, $category );
1121
				}
1122
			}
1123
		}
1124
1125
		$tags = get_the_terms( $post_id, 'post_tag' );
1126 View Code Duplication
		if ( is_array( $tags ) ) {
1127
			foreach ( $tags as $tag ) {
1128
				if ( '' != trim( $tag->name ) ) {
1129
					$post_tag_context = sprintf(
1130
						_x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
1131
						$tag->name
1132
					);
1133
					/**
1134
					 * Filter the "In Tag" line displayed in the post context below each Related Post.
1135
					 *
1136
					 * @module related-posts
1137
					 *
1138
					 * @since 3.2.0
1139
					 *
1140
					 * @param string $post_tag_context "In Tag" line displayed in the post context below each Related Post.
1141
					 * @param array $tag Array containing information about the tag.
1142
					 */
1143
					return apply_filters( 'jetpack_relatedposts_post_tag_context', $post_tag_context, $tag );
1144
				}
1145
			}
1146
		}
1147
1148
		$comment_count = get_comments_number( $post_id );
1149
		if ( $comment_count > 0 ) {
1150
			return sprintf(
1151
				_n( 'With 1 comment', 'With %s comments', $comment_count, 'jetpack' ),
1152
				number_format_i18n( $comment_count )
1153
			);
1154
		}
1155
1156
		return __( 'Similar post', 'jetpack' );
1157
	}
1158
1159
	/**
1160
	 * Logs clicks for clickthrough analysis and related result tuning.
1161
	 *
1162
	 * @return null
1163
	 */
1164
	protected function _log_click( $post_id, $to_post_id, $link_position ) {
0 ignored issues
show
Unused Code introduced by
The parameter $post_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $to_post_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $link_position is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1165
1166
	}
1167
1168
	/**
1169
	 * Determines if the current post is able to use related posts.
1170
	 *
1171
	 * @uses self::get_options, is_admin, is_single, apply_filters
1172
	 * @return bool
1173
	 */
1174
	protected function _enabled_for_request() {
1175
		// Default to enabled
1176
		$enabled = true;
1177
1178
		// Must have feature enabled
1179
		$options = $this->get_options();
1180
		if ( ! $options['enabled'] ) {
1181
			$enabled = false;
1182
		}
1183
1184
		// Only run for frontend pages
1185
		if ( is_admin() ) {
1186
			$enabled = false;
1187
		}
1188
1189
		// Only run for standalone posts
1190
		if ( ! is_single() ) {
1191
			$enabled = false;
1192
		}
1193
1194
		/**
1195
		 * Filter the Enabled value to allow related posts to be shown on pages as well.
1196
		 *
1197
		 * @module related-posts
1198
		 *
1199
		 * @since 3.3.0
1200
		 *
1201
		 * @param bool $enabled Should Related Posts be enabled on the current page.
1202
		 */
1203
		return apply_filters( 'jetpack_relatedposts_filter_enabled_for_request', $enabled );
1204
	}
1205
1206
	/**
1207
	 * Adds filters and enqueues assets.
1208
	 *
1209
	 * @uses self::_enqueue_assets, self::_setup_shortcode, add_filter
1210
	 * @return null
1211
	 */
1212
	protected function _action_frontend_init_page() {
1213
		$this->_enqueue_assets( true, true );
1214
		$this->_setup_shortcode();
1215
1216
		add_filter( 'the_content', array( $this, 'filter_add_target_to_dom' ), 40 );
1217
	}
1218
1219
	/**
1220
	 * Enqueues assets needed to do async loading of related posts.
1221
	 *
1222
	 * @uses wp_enqueue_script, wp_enqueue_style, plugins_url
1223
	 * @return null
1224
	 */
1225
	protected function _enqueue_assets( $script, $style ) {
1226
		if ( $script ) {
1227
			wp_enqueue_script( 'jetpack_related-posts', plugins_url( 'related-posts.js', __FILE__ ), array( 'jquery' ), self::VERSION );
1228
			$related_posts_js_options = array(
1229
				/**
1230
				 * Filter each Related Post Heading structure.
1231
				 *
1232
				 * @since 4.0.0
1233
				 *
1234
				 * @param string $str Related Post Heading structure. Default to h4.
1235
				 */
1236
				'post_heading' => apply_filters( 'jetpack_relatedposts_filter_post_heading', esc_attr( 'h4' ) ),
1237
			);
1238
			wp_localize_script( 'jetpack_related-posts', 'related_posts_js_options', $related_posts_js_options );
1239
		}
1240
		if ( $style ){
1241
			if( is_rtl() ) {
1242
				wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'rtl/related-posts-rtl.css', __FILE__ ), array(), self::VERSION );
1243
			} else {
1244
				wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'related-posts.css', __FILE__ ), array(), self::VERSION );
1245
			}
1246
		}
1247
	}
1248
1249
	/**
1250
	 * Sets up the shortcode processing.
1251
	 *
1252
	 * @uses add_filter, add_shortcode
1253
	 * @return null
1254
	 */
1255
	protected function _setup_shortcode() {
1256
		add_filter( 'the_content', array( $this, 'test_for_shortcode' ), 0 );
1257
1258
		add_shortcode( self::SHORTCODE, array( $this, 'get_target_html' ) );
1259
	}
1260
1261
	protected function _allow_feature_toggle() {
1262
		if ( null === $this->_allow_feature_toggle ) {
1263
			/**
1264
			 * Filter the display of the Related Posts toggle in Settings > Reading.
1265
			 *
1266
			 * @module related-posts
1267
			 *
1268
			 * @since 2.8.0
1269
			 *
1270
			 * @param bool false Display a feature toggle. Default to false.
1271
			 */
1272
			$this->_allow_feature_toggle = apply_filters( 'jetpack_relatedposts_filter_allow_feature_toggle', false );
1273
		}
1274
		return $this->_allow_feature_toggle;
1275
	}
1276
}
1277
1278
class Jetpack_RelatedPosts_Raw extends Jetpack_RelatedPosts {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
1279
	protected $_query_name;
1280
1281
	/**
1282
	 * Allows callers of this class to tag each query with a unique name for tracking purposes.
1283
	 *
1284
	 * @param string $name
1285
	 * @return Jetpack_RelatedPosts_Raw
1286
	 */
1287
	public function set_query_name( $name ) {
1288
		$this->_query_name = (string) $name;
1289
		return $this;
1290
	}
1291
1292
	/**
1293
	 * The raw related posts class can be used by other plugins or themes
1294
	 * to get related content. This class wraps the existing RelatedPosts
1295
	 * logic thus we never want to add anything to the DOM or do anything
1296
	 * for event hooks. We will also not present any settings for this
1297
	 * class and keep it enabled as calls to this class is done
1298
	 * programmatically.
1299
	 */
1300
	public function action_admin_init() {}
1301
	public function action_frontend_init() {}
1302
	public function get_options() {
1303
		return array(
1304
			'enabled' => true,
1305
		);
1306
	}
1307
1308
	/**
1309
	 * Workhorse method to return array of related posts ids matched by ElasticSearch.
1310
	 *
1311
	 * @param int $post_id
1312
	 * @param int $size
1313
	 * @param array $filters
1314
	 * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body
1315
	 * @return array
1316
	 */
1317
	protected function _get_related_posts( $post_id, $size, array $filters ) {
1318
		$hits = $this->_filter_non_public_posts(
1319
			$this->_get_related_post_ids(
1320
				$post_id,
1321
				$size,
1322
				$filters
1323
			)
1324
		);
1325
1326
		/** This filter is already documented in modules/related-posts/related-posts.php */
1327
		$hits = apply_filters( 'jetpack_relatedposts_filter_hits', $hits, $post_id );
1328
1329
		return $hits;
1330
	}
1331
}
1332