Completed
Push — branch-4.0 ( fc0d6f...bf547c )
by
unknown
08:22
created

Jetpack_RelatedPosts::_allow_feature_toggle()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
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
		if ( ! class_exists( 'Jetpack_Media_Summary' ) ) {
77
			jetpack_require_lib( 'class.media-summary' );
78
		}
79
	}
80
81
	/**
82
	 * =================
83
	 * ACTIONS & FILTERS
84
	 * =================
85
	 */
86
87
	/**
88
	 * Add a checkbox field to Settings > Reading for enabling related posts.
89
	 *
90
	 * @action admin_init
91
	 * @uses add_settings_field, __, register_setting, add_action
92
	 * @return null
93
	 */
94
	public function action_admin_init() {
95
96
		// Add the setting field [jetpack_relatedposts] and place it in Settings > Reading
97
		add_settings_field( 'jetpack_relatedposts', '<span id="jetpack_relatedposts">' . __( 'Related posts', 'jetpack' ) . '</span>', array( $this, 'print_setting_html' ), 'reading' );
98
		register_setting( 'reading', 'jetpack_relatedposts', array( $this, 'parse_options' ) );
99
		add_action('admin_head', array( $this, 'print_setting_head' ) );
100
101
		if( 'options-reading.php' == $GLOBALS['pagenow'] ) {
102
			// Enqueue style for live preview on the reading settings page
103
			$this->_enqueue_assets( false, true );
104
		}
105
	}
106
107
	/**
108
	 * Load related posts assets if it's a elegiable frontend page or execute search and return JSON if it's an endpoint request.
109
	 *
110
	 * @global $_GET
111
	 * @action wp
112
	 * @uses add_shortcode, get_the_ID
113
	 * @returns null
114
	 */
115
	public function action_frontend_init() {
116
		// Add a shortcode handler that outputs nothing, this gets overridden later if we can display related content
117
		add_shortcode( self::SHORTCODE, array( $this, 'get_target_html_unsupported' ) );
118
119
		if ( ! $this->_enabled_for_request() )
120
			return;
121
122
		if ( isset( $_GET['relatedposts'] ) ) {
123
			$excludes = array();
124
			if ( isset( $_GET['relatedposts_exclude'] ) ) {
125
				$excludes = explode( ',', $_GET['relatedposts_exclude'] );
126
			}
127
128
			$this->_action_frontend_init_ajax( $excludes );
129
		} else {
130
			if ( isset( $_GET['relatedposts_hit'], $_GET['relatedposts_origin'], $_GET['relatedposts_position'] ) ) {
131
				$this->_log_click( $_GET['relatedposts_origin'], get_the_ID(), $_GET['relatedposts_position'] );
132
				$this->_previous_post_id = (int) $_GET['relatedposts_origin'];
133
			}
134
135
			$this->_action_frontend_init_page();
136
		}
137
138
	}
139
140
	/**
141
	 * Adds a target to the post content to load related posts into if a shortcode for it did not already exist.
142
	 *
143
	 * @filter the_content
144
	 * @param string $content
145
	 * @returns string
146
	 */
147
	public function filter_add_target_to_dom( $content ) {
148
		if ( !$this->_found_shortcode ) {
149
			$content .= "\n" . $this->get_target_html();
150
		}
151
152
		return $content;
153
	}
154
155
	/**
156
	 * Looks for our shortcode on the unfiltered content, this has to execute early.
157
	 *
158
	 * @filter the_content
159
	 * @param string $content
160
	 * @uses has_shortcode
161
	 * @returns string
162
	 */
163
	public function test_for_shortcode( $content ) {
164
		$this->_found_shortcode = has_shortcode( $content, self::SHORTCODE );
165
166
		return $content;
167
	}
168
169
	/**
170
	 * Returns the HTML for the related posts section.
171
	 *
172
	 * @uses esc_html__, apply_filters
173
	 * @returns string
174
	 */
175
	public function get_target_html() {
176
		$options = $this->get_options();
177
178
		if ( $options['show_headline'] ) {
179
			$headline = sprintf(
180
				'<h3 class="jp-relatedposts-headline"><em>%s</em></h3>',
181
				esc_html__( 'Related', 'jetpack' )
182
			);
183
		} else {
184
			$headline = '';
185
		}
186
187
		/**
188
		 * Filter the Related Posts headline.
189
		 *
190
		 * @module related-posts
191
		 *
192
		 * @since 3.0.0
193
		 *
194
		 * @param string $headline Related Posts heading.
195
		 */
196
		$headline = apply_filters( 'jetpack_relatedposts_filter_headline', $headline );
197
198
		if ( $this->_previous_post_id ) {
199
			$exclude = "data-exclude='{$this->_previous_post_id}'";
200
		} else {
201
			$exclude = "";
202
		}
203
204
		return <<<EOT
205
<div id='jp-relatedposts' class='jp-relatedposts' $exclude>
206
	$headline
207
</div>
208
EOT;
209
	}
210
211
	/**
212
	 * 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.
213
	 *
214
	 * @returns string
215
	 */
216
	public function get_target_html_unsupported() {
217
		return "\n\n<!-- Jetpack Related Posts is not supported in this context. -->\n\n";
218
	}
219
220
	/**
221
	 * ========================
222
	 * PUBLIC UTILITY FUNCTIONS
223
	 * ========================
224
	 */
225
226
	/**
227
	 * Gets options set for Jetpack_RelatedPosts and merge with defaults.
228
	 *
229
	 * @uses Jetpack_Options::get_option, apply_filters
230
	 * @return array
231
	 */
232
	public function get_options() {
233
		if ( null === $this->_options ) {
234
			$this->_options = Jetpack_Options::get_option( 'relatedposts' );
235
			if ( ! is_array( $this->_options ) )
236
				$this->_options = array();
237
			if ( ! isset( $this->_options['enabled'] ) )
238
				$this->_options['enabled'] = true;
239
			if ( ! isset( $this->_options['show_headline'] ) )
240
				$this->_options['show_headline'] = true;
241
			if ( ! isset( $this->_options['show_thumbnails'] ) )
242
				$this->_options['show_thumbnails'] = false;
243
			if ( empty( $this->_options['size'] ) || (int)$this->_options['size'] < 1 )
244
				$this->_options['size'] = 3;
245
246
			/**
247
			 * Filter Related Posts basic options.
248
			 *
249
			 * @module related-posts
250
			 *
251
			 * @since 2.8.0
252
			 *
253
			 * @param array $this->_options Array of basic Related Posts options.
254
			 */
255
			$this->_options = apply_filters( 'jetpack_relatedposts_filter_options', $this->_options );
256
		}
257
258
		return $this->_options;
259
	}
260
261
	/**
262
	 * Parses input and returnes normalized options array.
263
	 *
264
	 * @param array $input
265
	 * @uses self::get_options
266
	 * @return array
267
	 */
268
	public function parse_options( $input ) {
269
		$current = $this->get_options();
270
271
		if ( !is_array( $input ) )
272
			$input = array();
273
274
		if ( isset( $input['enabled'] ) && '1' == $input['enabled'] ) {
275
			$current['enabled'] = true;
276
			$current['show_headline'] = ( isset( $input['show_headline'] ) && '1' == $input['show_headline'] );
277
			$current['show_thumbnails'] = ( isset( $input['show_thumbnails'] ) && '1' == $input['show_thumbnails'] );
278
		} else {
279
			$current['enabled'] = false;
280
		}
281
282
		if ( isset( $input['size'] ) && (int)$input['size'] > 0 )
283
			$current['size'] = (int)$input['size'];
284
		else
285
			$current['size'] = null;
286
287
		return $current;
288
	}
289
290
	/**
291
	 * HTML for admin settings page.
292
	 *
293
	 * @uses self::get_options, checked, esc_html__
294
	 * @returns null
295
	 */
296
	public function print_setting_html() {
297
		$options = $this->get_options();
298
299
		$ui_settings_template = <<<EOT
300
<ul id="settings-reading-relatedposts-customize">
301
	<li>
302
		<label><input name="jetpack_relatedposts[show_headline]" type="checkbox" value="1" %s /> %s</label>
303
	</li>
304
	<li>
305
		<label><input name="jetpack_relatedposts[show_thumbnails]" type="checkbox" value="1" %s /> %s</label>
306
	</li>
307
</ul>
308
<div id='settings-reading-relatedposts-preview'>
309
	%s
310
	<div id="jp-relatedposts" class="jp-relatedposts"></div>
311
</div>
312
EOT;
313
		$ui_settings = sprintf(
314
			$ui_settings_template,
315
			checked( $options['show_headline'], true, false ),
316
			esc_html__( 'Show a "Related" header to more clearly separate the related section from posts', 'jetpack' ),
317
			checked( $options['show_thumbnails'], true, false ),
318
			esc_html__( 'Use a large and visually striking layout', 'jetpack' ),
319
			esc_html__( 'Preview:', 'jetpack' )
320
		);
321
322
		if ( !$this->_allow_feature_toggle() ) {
323
			$template = <<<EOT
324
<input type="hidden" name="jetpack_relatedposts[enabled]" value="1" />
325
%s
326
EOT;
327
			printf(
328
				$template,
329
				$ui_settings
330
			);
331
		} else {
332
			$template = <<<EOT
333
<ul id="settings-reading-relatedposts">
334
	<li>
335
		<label><input type="radio" name="jetpack_relatedposts[enabled]" value="0" class="tog" %s /> %s</label>
336
	</li>
337
	<li>
338
		<label><input type="radio" name="jetpack_relatedposts[enabled]" value="1" class="tog" %s /> %s</label>
339
		%s
340
	</li>
341
</ul>
342
EOT;
343
			printf(
344
				$template,
345
				checked( $options['enabled'], false, false ),
346
				esc_html__( 'Hide related content after posts', 'jetpack' ),
347
				checked( $options['enabled'], true, false ),
348
				esc_html__( 'Show related content after posts', 'jetpack' ),
349
				$ui_settings
350
			);
351
		}
352
	}
353
354
	/**
355
	 * Head JS/CSS for admin settings page.
356
	 *
357
	 * @uses esc_html__
358
	 * @returns null
359
	 */
360
	public function print_setting_head() {
361
362
		// only dislay the Related Posts JavaScript on the Reading Settings Admin Page
363
		$current_screen =  get_current_screen();
364
		if( 'options-reading' != $current_screen->id )
365
			return;
366
367
		$related_headline = sprintf(
368
			'<h3 class="jp-relatedposts-headline"><em>%s</em></h3>',
369
			esc_html__( 'Related', 'jetpack' )
370
		);
371
372
		$href_params = 'class="jp-relatedposts-post-a" href="#jetpack_relatedposts" rel="nofollow" data-origin="0" data-position="0"';
373
		$related_with_images = <<<EOT
374
<div class="jp-relatedposts-items jp-relatedposts-items-visual">
375
	<div class="jp-relatedposts-post jp-relatedposts-post0 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
376
		<a $href_params>
377
			<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">
378
		</a>
379
		<h4 class="jp-relatedposts-post-title">
380
			<a $href_params>Big iPhone/iPad Update Now Available</a>
381
		</h4>
382
		<p class="jp-relatedposts-post-excerpt">Big iPhone/iPad Update Now Available</p>
383
		<p class="jp-relatedposts-post-context">In "Mobile"</p>
384
	</div>
385
	<div class="jp-relatedposts-post jp-relatedposts-post1 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
386
		<a $href_params>
387
			<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">
388
		</a>
389
		<h4 class="jp-relatedposts-post-title">
390
			<a $href_params>The WordPress for Android App Gets a Big Facelift</a>
391
		</h4>
392
		<p class="jp-relatedposts-post-excerpt">The WordPress for Android App Gets a Big Facelift</p>
393
		<p class="jp-relatedposts-post-context">In "Mobile"</p>
394
	</div>
395
	<div class="jp-relatedposts-post jp-relatedposts-post2 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
396
		<a $href_params>
397
			<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">
398
		</a>
399
		<h4 class="jp-relatedposts-post-title">
400
			<a $href_params>Upgrade Focus: VideoPress For Weddings</a>
401
		</h4>
402
		<p class="jp-relatedposts-post-excerpt">Upgrade Focus: VideoPress For Weddings</p>
403
		<p class="jp-relatedposts-post-context">In "Upgrade"</p>
404
	</div>
405
</div>
406
EOT;
407
		$related_with_images = str_replace( "\n", '', $related_with_images );
408
		$related_without_images = <<<EOT
409
<div class="jp-relatedposts-items jp-relatedposts-items-minimal">
410
	<p class="jp-relatedposts-post jp-relatedposts-post0" data-post-id="0" data-post-format="image">
411
		<span class="jp-relatedposts-post-title"><a $href_params>Big iPhone/iPad Update Now Available</a></span>
412
		<span class="jp-relatedposts-post-context">In "Mobile"</span>
413
	</p>
414
	<p class="jp-relatedposts-post jp-relatedposts-post1" data-post-id="0" data-post-format="image">
415
		<span class="jp-relatedposts-post-title"><a $href_params>The WordPress for Android App Gets a Big Facelift</a></span>
416
		<span class="jp-relatedposts-post-context">In "Mobile"</span>
417
	</p>
418
	<p class="jp-relatedposts-post jp-relatedposts-post2" data-post-id="0" data-post-format="image">
419
		<span class="jp-relatedposts-post-title"><a $href_params>Upgrade Focus: VideoPress For Weddings</a></span>
420
		<span class="jp-relatedposts-post-context">In "Upgrade"</span>
421
	</p>
422
</div>
423
EOT;
424
		$related_without_images = str_replace( "\n", '', $related_without_images );
425
426
		if ( $this->_allow_feature_toggle() ) {
427
			$extra_css = '#settings-reading-relatedposts-customize { padding-left:2em; margin-top:.5em; }';
428
		} else {
429
			$extra_css = '';
430
		}
431
432
		echo <<<EOT
433
<style type="text/css">
434
	#settings-reading-relatedposts .disabled { opacity:.5; filter:Alpha(opacity=50); }
435
	#settings-reading-relatedposts-preview .jp-relatedposts { background:#fff; padding:.5em; width:75%; }
436
	$extra_css
437
</style>
438
<script type="text/javascript">
439
	jQuery( document ).ready( function($) {
440
		var update_ui = function() {
441
			var is_enabled = true;
442
			if ( 'radio' == $( 'input[name="jetpack_relatedposts[enabled]"]' ).attr('type') ) {
443
				if ( '0' == $( 'input[name="jetpack_relatedposts[enabled]"]:checked' ).val() ) {
444
					is_enabled = false;
445
				}
446
			}
447
			if ( is_enabled ) {
448
				$( '#settings-reading-relatedposts-customize' )
449
					.removeClass( 'disabled' )
450
					.find( 'input' )
451
					.attr( 'disabled', false );
452
				$( '#settings-reading-relatedposts-preview' )
453
					.removeClass( 'disabled' );
454
			} else {
455
				$( '#settings-reading-relatedposts-customize' )
456
					.addClass( 'disabled' )
457
					.find( 'input' )
458
					.attr( 'disabled', true );
459
				$( '#settings-reading-relatedposts-preview' )
460
					.addClass( 'disabled' );
461
			}
462
		};
463
464
		var update_preview = function() {
465
			var html = '';
466
			if ( $( 'input[name="jetpack_relatedposts[show_headline]"]:checked' ).size() ) {
467
				html += '$related_headline';
468
			}
469
			if ( $( 'input[name="jetpack_relatedposts[show_thumbnails]"]:checked' ).size() ) {
470
				html += '$related_with_images';
471
			} else {
472
				html += '$related_without_images';
473
			}
474
			$( '#settings-reading-relatedposts-preview .jp-relatedposts' )
475
				.html( html )
476
				.show();
477
		};
478
479
		// Update on load
480
		update_preview();
481
		update_ui();
482
483
		// Update on change
484
		$( '#settings-reading-relatedposts-customize input' )
485
			.change( update_preview );
486
		$( '#settings-reading-relatedposts' )
487
			.find( 'input.tog' )
488
			.change( update_ui );
489
	});
490
</script>
491
EOT;
492
	}
493
494
	/**
495
	 * Gets an array of related posts that match the given post_id.
496
	 *
497
	 * @param int $post_id
498
	 * @param array $args - params to use when building ElasticSearch filters to narrow down the search domain.
499
	 * @uses self::get_options, get_post_type, wp_parse_args, apply_filters
500
	 * @return array
501
	 */
502
	public function get_for_post_id( $post_id, array $args ) {
503
		$options = $this->get_options();
504
505
		if ( ! empty( $args['size'] ) )
506
			$options['size'] = $args['size'];
507
508
		if ( ! $options['enabled'] || 0 == (int)$post_id || empty( $options['size'] ) )
509
			return array();
510
511
		$defaults = array(
512
			'size' => (int)$options['size'],
513
			'post_type' => get_post_type( $post_id ),
514
			'post_formats' => array(),
515
			'has_terms' => array(),
516
			'date_range' => array(),
517
			'exclude_post_ids' => array(),
518
		);
519
		$args = wp_parse_args( $args, $defaults );
520
		/**
521
		 * Filter the arguments used to retrieve a list of Related Posts.
522
		 *
523
		 * @module related-posts
524
		 *
525
		 * @since 2.8.0
526
		 *
527
		 * @param array $args Array of options to retrieve Related Posts.
528
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
529
		 */
530
		$args = apply_filters( 'jetpack_relatedposts_filter_args', $args, $post_id );
531
532
		$filters = $this->_get_es_filters_from_args( $post_id, $args );
533
		/**
534
		 * Filter ElasticSearch options used to calculate Related Posts.
535
		 *
536
		 * @module related-posts
537
		 *
538
		 * @since 2.8.0
539
		 *
540
		 * @param array $filters Array of ElasticSearch filters based on the post_id and args.
541
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
542
		 */
543
		$filters = apply_filters( 'jetpack_relatedposts_filter_filters', $filters, $post_id );
544
545
		$results = $this->_get_related_posts( $post_id, $args['size'], $filters );
546
		/**
547
		 * Filter the array of related posts matched by ElasticSearch.
548
		 *
549
		 * @module related-posts
550
		 *
551
		 * @since 2.8.0
552
		 *
553
		 * @param array $results Array of related posts matched by ElasticSearch.
554
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
555
		 */
556
		return apply_filters( 'jetpack_relatedposts_returned_results', $results, $post_id );
557
	}
558
559
	/**
560
	 * =========================
561
	 * PRIVATE UTILITY FUNCTIONS
562
	 * =========================
563
	 */
564
565
	/**
566
	 * Creates an array of ElasticSearch filters based on the post_id and args.
567
	 *
568
	 * @param int $post_id
569
	 * @param array $args
570
	 * @uses apply_filters, get_post_types, get_post_format_strings
571
	 * @return array
572
	 */
573
	protected function _get_es_filters_from_args( $post_id, array $args ) {
574
		$filters = array();
575
576
		/**
577
		 * Filter the terms used to search for Related Posts.
578
		 *
579
		 * @module related-posts
580
		 *
581
		 * @since 2.8.0
582
		 *
583
		 * @param array $args['has_terms'] Array of terms associated to the Related Posts.
584
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
585
		 */
586
		$args['has_terms'] = apply_filters( 'jetpack_relatedposts_filter_has_terms', $args['has_terms'], $post_id );
587
		if ( ! empty( $args['has_terms'] ) ) {
588
			foreach( (array)$args['has_terms'] as $term ) {
589
				if ( mb_strlen( $term->taxonomy ) ) {
590
					switch ( $term->taxonomy ) {
591
						case 'post_tag':
592
							$tax_fld = 'tag.slug';
593
							break;
594
						case 'category':
595
							$tax_fld = 'category.slug';
596
							break;
597
						default:
598
							$tax_fld = 'taxonomy.' . $term->taxonomy . '.slug';
599
							break;
600
					}
601
					$filters[] = array( 'term' => array( $tax_fld => $term->slug ) );
602
				}
603
			}
604
		}
605
606
		/**
607
		 * Filter the Post Types where we search Related Posts.
608
		 *
609
		 * @module related-posts
610
		 *
611
		 * @since 2.8.0
612
		 *
613
		 * @param array $args['post_type'] Array of Post Types.
614
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
615
		 */
616
		$args['post_type'] = apply_filters( 'jetpack_relatedposts_filter_post_type', $args['post_type'], $post_id );
617
		$valid_post_types = get_post_types();
618
		if ( is_array( $args['post_type'] ) ) {
619
			$sanitized_post_types = array();
620
			foreach ( $args['post_type'] as $pt ) {
621
				if ( in_array( $pt, $valid_post_types ) )
622
					$sanitized_post_types[] = $pt;
623
			}
624
			if ( ! empty( $sanitized_post_types ) )
625
				$filters[] = array( 'terms' => array( 'post_type' => $sanitized_post_types ) );
626
		} else if ( in_array( $args['post_type'], $valid_post_types ) && 'all' != $args['post_type'] ) {
627
			$filters[] = array( 'term' => array( 'post_type' => $args['post_type'] ) );
628
		}
629
630
		/**
631
		 * Filter the Post Formats where we search Related Posts.
632
		 *
633
		 * @module related-posts
634
		 *
635
		 * @since 3.3.0
636
		 *
637
		 * @param array $args['post_formats'] Array of Post Formats.
638
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
639
		 */
640
		$args['post_formats'] = apply_filters( 'jetpack_relatedposts_filter_post_formats', $args['post_formats'], $post_id );
641
		$valid_post_formats = get_post_format_strings();
642
		$sanitized_post_formats = array();
643
		foreach ( $args['post_formats'] as $pf ) {
644
			if ( array_key_exists( $pf, $valid_post_formats ) ) {
645
				$sanitized_post_formats[] = $pf;
646
			}
647
		}
648
		if ( ! empty( $sanitized_post_formats ) ) {
649
			$filters[] = array( 'terms' => array( 'post_format' => $sanitized_post_formats ) );
650
		}
651
652
		/**
653
		 * Filter the date range used to search Related Posts.
654
		 *
655
		 * @module related-posts
656
		 *
657
		 * @since 2.8.0
658
		 *
659
		 * @param array $args['date_range'] Array of a month interval where we search Related Posts.
660
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
661
		 */
662
		$args['date_range'] = apply_filters( 'jetpack_relatedposts_filter_date_range', $args['date_range'], $post_id );
663
		if ( is_array( $args['date_range'] ) && ! empty( $args['date_range'] ) ) {
664
			$args['date_range'] = array_map( 'intval', $args['date_range'] );
665
			if ( !empty( $args['date_range']['from'] ) && !empty( $args['date_range']['to'] ) ) {
666
				$filters[] = array(
667
					'range' => array(
668
						'date_gmt' => $this->_get_coalesced_range( $args['date_range'] ),
669
					)
670
				);
671
			}
672
		}
673
674
		/**
675
		 * Filter the Post IDs excluded from appearing in Related Posts.
676
		 *
677
		 * @module related-posts
678
		 *
679
		 * @since 2.9.0
680
		 *
681
		 * @param array $args['exclude_post_ids'] Array of Post IDs.
682
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
683
		 */
684
		$args['exclude_post_ids'] = apply_filters( 'jetpack_relatedposts_filter_exclude_post_ids', $args['exclude_post_ids'], $post_id );
685
		if ( !empty( $args['exclude_post_ids'] ) && is_array( $args['exclude_post_ids'] ) ) {
686
			foreach ( $args['exclude_post_ids'] as $exclude_post_id) {
687
				$exclude_post_id = (int)$exclude_post_id;
688
689
				if ( $exclude_post_id > 0 )
690
					$filters[] = array( 'not' => array( 'term' => array( 'post_id' => $exclude_post_id ) ) );
691
			}
692
		}
693
694
		return $filters;
695
	}
696
697
	/**
698
	 * Takes a range and coalesces it into a month interval bracketed by a time as determined by the blog_id to enhance caching.
699
	 *
700
	 * @param array $date_range
701
	 * @return array
702
	 */
703
	protected function _get_coalesced_range( array $date_range ) {
704
		$now = time();
705
		$coalesce_time = $this->_blog_id_wpcom % 86400;
706
		$current_time = $now - strtotime( 'today', $now );
707
708
		if ( $current_time < $coalesce_time && '01' == date( 'd', $now ) ) {
709
			// Move back 1 period
710
			return array(
711
				'from' => date( 'Y-m-01', strtotime( '-1 month', $date_range['from'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
712
				'to'   => date( 'Y-m-01', $date_range['to'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
713
			);
714
		} else {
715
			// Use current period
716
			return array(
717
				'from' => date( 'Y-m-01', $date_range['from'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
718
				'to'   => date( 'Y-m-01', strtotime( '+1 month', $date_range['to'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
719
			);
720
		}
721
	}
722
723
	/**
724
	 * Generate and output ajax response for related posts API call.
725
	 * NOTE: Calls exit() to end all further processing after payload has been outputed.
726
	 *
727
	 * @param array $excludes array of post_ids to exclude
728
	 * @uses send_nosniff_header, self::get_for_post_id, get_the_ID
729
	 * @return null
730
	 */
731
	protected function _action_frontend_init_ajax( array $excludes ) {
732
		define( 'DOING_AJAX', true );
733
734
		header( 'Content-type: application/json; charset=utf-8' ); // JSON can only be UTF-8
735
		send_nosniff_header();
736
737
		$related_posts = $this->get_for_post_id(
738
			get_the_ID(),
739
			array(
740
				'exclude_post_ids' => $excludes,
741
			)
742
		);
743
744
		$options = $this->get_options();
745
746
		$response = array(
747
			'version' => self::VERSION,
748
			'show_thumbnails' => (bool) $options['show_thumbnails'],
749
			'items' => array(),
750
		);
751
752
		if ( count( $related_posts ) == $options['size'] )
753
			$response['items'] = $related_posts;
754
755
		echo json_encode( $response );
756
757
		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...
758
	}
759
760
	/**
761
	 * Returns a UTF-8 encoded array of post information for the given post_id
762
	 *
763
	 * @param int $post_id
764
	 * @param int $position
765
	 * @param int $origin The post id that this is related to
766
	 * @uses get_post, get_permalink, remove_query_arg, get_post_format, apply_filters
767
	 * @return array
768
	 */
769
	protected function _get_related_post_data_for_post( $post_id, $position, $origin ) {
770
		$post = get_post( $post_id );
771
772
		return array(
773
			'id' => $post->ID,
774
			'url' => get_permalink( $post->ID ),
775
			'url_meta' => array( 'origin' => $origin, 'position' => $position ),
776
			'title' => $this->_to_utf8( $this->_get_title( $post->post_title, $post->post_content ) ),
777
			'date' => get_the_date( '', $post->ID ),
778
			'format' => get_post_format( $post->ID ),
779
			'excerpt' => html_entity_decode( $this->_to_utf8( $this->_get_excerpt( $post->post_excerpt, $post->post_content ) ), ENT_QUOTES, 'UTF-8' ),
780
			/**
781
			 * Filters the rel attribute for the Related Posts' links.
782
			 *
783
			 * @module related-posts
784
			 *
785
			 * @since 3.7.0
786
			 *
787
			 * @param string nofollow Link rel attribute for Related Posts' link. Default is nofollow.
788
			 * @param int $post->ID Post ID.
789
			 */
790
			'rel' => apply_filters( 'jetpack_relatedposts_filter_post_link_rel', 'nofollow', $post->ID ),
791
			/**
792
			 * Filter the context displayed below each Related Post.
793
			 *
794
			 * @module related-posts
795
			 *
796
			 * @since 3.0.0
797
			 *
798
			 * @param string $this->_to_utf8( $this->_generate_related_post_context( $post->ID ) ) Context displayed below each related post.
799
			 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
800
			 */
801
			'context' => apply_filters(
802
				'jetpack_relatedposts_filter_post_context',
803
				$this->_to_utf8( $this->_generate_related_post_context( $post->ID ) ),
804
				$post->ID
805
			),
806
			'img' => $this->_generate_related_post_image_params( $post->ID ),
807
			/**
808
			 * Filter the post css classes added on HTML markup.
809
			 *
810
			 * @module related-posts
811
			 *
812
			 * @since 3.8.0
813
			 *
814
			 * @param array array() CSS classes added on post HTML markup.
815
			 * @param string $post_id Post ID.
816
			 */
817
			'classes' => apply_filters(
818
				'jetpack_relatedposts_filter_post_css_classes',
819
				array(),
820
				$post->ID
821
			),
822
		);
823
	}
824
825
	/**
826
	 * Returns either the title or a small excerpt to use as title for post.
827
	 *
828
	 * @param string $post_title
829
	 * @param string $post_content
830
	 * @uses strip_shortcodes, wp_trim_words, __
831
	 * @return string
832
	 */
833
	protected function _get_title( $post_title, $post_content ) {
834
		if ( ! empty( $post_title ) ) {
835
			return wp_strip_all_tags( $post_title );
836
		}
837
838
		$post_title = wp_trim_words( wp_strip_all_tags( strip_shortcodes( $post_content ) ), 5, '…' );
839
		if ( ! empty( $post_title ) ) {
840
			return $post_title;
841
		}
842
843
		return __( 'Untitled Post', 'jetpack' );
844
	}
845
846
	/**
847
	 * Returns a plain text post excerpt for title attribute of links.
848
	 *
849
	 * @param string $post_excerpt
850
	 * @param string $post_content
851
	 * @uses strip_shortcodes, wp_strip_all_tags, wp_trim_words
852
	 * @return string
853
	 */
854
	protected function _get_excerpt( $post_excerpt, $post_content ) {
855
		if ( empty( $post_excerpt ) )
856
			$excerpt = $post_content;
857
		else
858
			$excerpt = $post_excerpt;
859
860
		return wp_trim_words( wp_strip_all_tags( strip_shortcodes( $excerpt ) ), 50, '…' );
861
	}
862
863
	/**
864
	 * Generates the thumbnail image to be used for the post. Uses the
865
	 * image as returned by Jetpack_PostImages::get_image()
866
	 *
867
	 * @param int $post_id
868
	 * @uses self::get_options, apply_filters, Jetpack_PostImages::get_image, Jetpack_PostImages::fit_image_url
869
	 * @return string
870
	 */
871
	protected function _generate_related_post_image_params( $post_id ) {
872
		$options = $this->get_options();
873
		$image_params = array(
874
			'src' => '',
875
			'width' => 0,
876
			'height' => 0,
877
		);
878
879
		if ( ! $options['show_thumbnails'] ) {
880
			return $image_params;
881
		}
882
883
		/**
884
		 * Filter the size of the Related Posts images.
885
		 *
886
		 * @module related-posts
887
		 *
888
		 * @since 2.8.0
889
		 *
890
		 * @param array array( 'width' => 350, 'height' => 200 ) Size of the images displayed below each Related Post.
891
		 */
892
		$thumbnail_size = apply_filters(
893
			'jetpack_relatedposts_filter_thumbnail_size',
894
			array( 'width' => 350, 'height' => 200 )
895
		);
896
		if ( !is_array( $thumbnail_size ) ) {
897
			$thumbnail_size = array(
898
				'width' => (int)$thumbnail_size,
899
				'height' => (int)$thumbnail_size
900
			);
901
		}
902
903
		// Try to get post image
904
		if ( class_exists( 'Jetpack_PostImages' ) ) {
905
			$img_url = '';
906
			$post_image = Jetpack_PostImages::get_image(
907
				$post_id,
908
				$thumbnail_size
909
			);
910
911
			if ( is_array($post_image) ) {
912
				$img_url = $post_image['src'];
913
			} elseif ( class_exists( 'Jetpack_Media_Summary' ) ) {
914
				$media = Jetpack_Media_Summary::get( $post_id );
915
916
				if ( is_array($media) && !empty( $media['image'] ) ) {
917
					$img_url = $media['image'];
918
				}
919
			}
920
921
			if ( !empty( $img_url ) ) {
922
				$image_params['width'] = $thumbnail_size['width'];
923
				$image_params['height'] = $thumbnail_size['height'];
924
				$image_params['src'] = Jetpack_PostImages::fit_image_url(
925
					$img_url,
926
					$thumbnail_size['width'],
927
					$thumbnail_size['height']
928
				);
929
			}
930
		}
931
932
		return $image_params;
933
	}
934
935
	/**
936
	 * Returns the string UTF-8 encoded
937
	 *
938
	 * @param string $text
939
	 * @return string
940
	 */
941
	protected function _to_utf8( $text ) {
942
		if ( $this->_convert_charset ) {
943
			return iconv( $this->_blog_charset, 'UTF-8', $text );
944
		} else {
945
			return $text;
946
		}
947
	}
948
949
	/**
950
	 * =============================================
951
	 * PROTECTED UTILITY FUNCTIONS EXTENDED BY WPCOM
952
	 * =============================================
953
	 */
954
955
	/**
956
	 * Workhorse method to return array of related posts matched by ElasticSearch.
957
	 *
958
	 * @param int $post_id
959
	 * @param int $size
960
	 * @param array $filters
961
	 * @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
962
	 * @return array
963
	 */
964
	protected function _get_related_posts( $post_id, $size, array $filters ) {
965
		$hits = $this->_filter_non_public_posts(
966
			$this->_get_related_post_ids(
967
				$post_id,
968
				$size,
969
				$filters
970
			)
971
		);
972
973
		/**
974
		 * Filter the Related Posts matched by ElasticSearch.
975
		 *
976
		 * @module related-posts
977
		 *
978
		 * @since 2.9.0
979
		 *
980
		 * @param array $hits Array of Post IDs matched by ElasticSearch.
981
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
982
		 */
983
		$hits = apply_filters( 'jetpack_relatedposts_filter_hits', $hits, $post_id );
984
985
		$related_posts = array();
986
		foreach ( $hits as $i => $hit ) {
987
			$related_posts[] = $this->_get_related_post_data_for_post( $hit['id'], $i, $post_id );
988
		}
989
		return $related_posts;
990
	}
991
992
	/**
993
	 * Get array of related posts matched by ElasticSearch.
994
	 *
995
	 * @param int $post_id
996
	 * @param int $size
997
	 * @param array $filters
998
	 * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body, get_post_meta, update_post_meta
999
	 * @return array
1000
	 */
1001
	protected function _get_related_post_ids( $post_id, $size, array $filters ) {
1002
		$now_ts = time();
1003
		$cache_meta_key = '_jetpack_related_posts_cache';
1004
1005
		$body = array(
1006
			'size' => (int) $size,
1007
		);
1008
1009
		if ( !empty( $filters ) )
1010
			$body['filter'] = array( 'and' => $filters );
1011
1012
		// Load all cached values
1013
		$cache = get_post_meta( $post_id, $cache_meta_key, true );
1014
		if ( empty( $cache ) )
1015
			$cache = array();
1016
1017
		// Build cache key
1018
		$cache_key = md5( serialize( $body ) );
1019
1020
		// Cache is valid! Return cached value.
1021
		if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) && $cache[ $cache_key ][ 'expires' ] > $now_ts ) {
1022
			return $cache[ $cache_key ][ 'payload' ];
1023
		}
1024
1025
		$response = wp_remote_post(
1026
			"https://public-api.wordpress.com/rest/v1/sites/{$this->_blog_id_wpcom}/posts/$post_id/related/",
1027
			array(
1028
				'timeout' => 10,
1029
				'user-agent' => 'jetpack_related_posts',
1030
				'sslverify' => true,
1031
				'body' => $body,
1032
			)
1033
		);
1034
1035
		// Oh no... return nothing don't cache errors.
1036
		if ( is_wp_error( $response ) ) {
1037
			if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) )
1038
				return $cache[ $cache_key ][ 'payload' ]; // return stale
1039
			else
1040
				return array();
1041
		}
1042
1043
		$results = json_decode( wp_remote_retrieve_body( $response ), true );
1044
		$related_posts = array();
1045
		if ( is_array( $results ) && !empty( $results['hits'] ) ) {
1046
			foreach( $results['hits'] as $hit ) {
1047
				$related_posts[] = array(
1048
					'id' => $hit['fields']['post_id'],
1049
				);
1050
			}
1051
		}
1052
1053
		// Copy all valid cache values
1054
		$new_cache = array();
1055
		foreach ( $cache as $k => $v ) {
1056
			if ( is_array( $v ) && $v[ 'expires' ] > $now_ts ) {
1057
				$new_cache[ $k ] = $v;
1058
			}
1059
		}
1060
1061
		// Set new cache value if valid
1062
		if ( ! empty( $related_posts ) ) {
1063
			$new_cache[ $cache_key ] = array(
1064
				'expires' => 12 * HOUR_IN_SECONDS + $now_ts,
1065
				'payload' => $related_posts,
1066
			);
1067
		}
1068
1069
		// Update cache
1070
		update_post_meta( $post_id, $cache_meta_key, $new_cache );
1071
1072
		return $related_posts;
1073
	}
1074
1075
	/**
1076
	 * Filter out any hits that are not public anymore.
1077
	 *
1078
	 * @param array $related_posts
1079
	 * @uses get_post_stati, get_post_status
1080
	 * @return array
1081
	 */
1082
	protected function _filter_non_public_posts( array $related_posts ) {
1083
		$public_stati = get_post_stati( array( 'public' => true ) );
1084
1085
		$filtered = array();
1086
		foreach ( $related_posts as $hit ) {
1087
			if ( in_array( get_post_status( $hit['id'] ), $public_stati ) ) {
1088
				$filtered[] = $hit;
1089
			}
1090
		}
1091
		return $filtered;
1092
	}
1093
1094
	/**
1095
	 * Generates a context for the related content (second line in related post output).
1096
	 * Order of importance:
1097
	 *   - First category (Not 'Uncategorized')
1098
	 *   - First post tag
1099
	 *   - Number of comments
1100
	 *
1101
	 * @param int $post_id
1102
	 * @uses get_the_category, get_the_terms, get_comments_number, number_format_i18n, __, _n
1103
	 * @return string
1104
	 */
1105
	protected function _generate_related_post_context( $post_id ) {
1106
		$categories = get_the_category( $post_id );
1107 View Code Duplication
		if ( is_array( $categories ) ) {
1108
			foreach ( $categories as $category ) {
1109
				if ( 'uncategorized' != $category->slug && '' != trim( $category->name ) ) {
1110
					$post_cat_context = sprintf(
1111
						_x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
1112
						$category->name
1113
					);
1114
					/**
1115
					 * Filter the "In Category" line displayed in the post context below each Related Post.
1116
					 *
1117
					 * @module related-posts
1118
					 *
1119
					 * @since 3.2.0
1120
					 *
1121
					 * @param string $post_cat_context "In Category" line displayed in the post context below each Related Post.
1122
					 * @param array $category Array containing information about the category.
1123
					 */
1124
					return apply_filters( 'jetpack_relatedposts_post_category_context', $post_cat_context, $category );
1125
				}
1126
			}
1127
		}
1128
1129
		$tags = get_the_terms( $post_id, 'post_tag' );
1130 View Code Duplication
		if ( is_array( $tags ) ) {
1131
			foreach ( $tags as $tag ) {
1132
				if ( '' != trim( $tag->name ) ) {
1133
					$post_tag_context = sprintf(
1134
						_x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
1135
						$tag->name
1136
					);
1137
					/**
1138
					 * Filter the "In Tag" line displayed in the post context below each Related Post.
1139
					 *
1140
					 * @module related-posts
1141
					 *
1142
					 * @since 3.2.0
1143
					 *
1144
					 * @param string $post_tag_context "In Tag" line displayed in the post context below each Related Post.
1145
					 * @param array $tag Array containing information about the tag.
1146
					 */
1147
					return apply_filters( 'jetpack_relatedposts_post_tag_context', $post_tag_context, $tag );
1148
				}
1149
			}
1150
		}
1151
1152
		$comment_count = get_comments_number( $post_id );
1153
		if ( $comment_count > 0 ) {
1154
			return sprintf(
1155
				_n( 'With 1 comment', 'With %s comments', $comment_count, 'jetpack' ),
1156
				number_format_i18n( $comment_count )
1157
			);
1158
		}
1159
1160
		return __( 'Similar post', 'jetpack' );
1161
	}
1162
1163
	/**
1164
	 * Logs clicks for clickthrough analysis and related result tuning.
1165
	 *
1166
	 * @return null
1167
	 */
1168
	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...
1169
1170
	}
1171
1172
	/**
1173
	 * Determines if the current post is able to use related posts.
1174
	 *
1175
	 * @uses self::get_options, is_admin, is_single, apply_filters
1176
	 * @return bool
1177
	 */
1178
	protected function _enabled_for_request() {
1179
		// Default to enabled
1180
		$enabled = true;
1181
1182
		// Must have feature enabled
1183
		$options = $this->get_options();
1184
		if ( ! $options['enabled'] ) {
1185
			$enabled = false;
1186
		}
1187
1188
		// Only run for frontend pages
1189
		if ( is_admin() ) {
1190
			$enabled = false;
1191
		}
1192
1193
		// Only run for standalone posts
1194
		if ( ! is_single() ) {
1195
			$enabled = false;
1196
		}
1197
1198
		/**
1199
		 * Filter the Enabled value to allow related posts to be shown on pages as well.
1200
		 *
1201
		 * @module related-posts
1202
		 *
1203
		 * @since 3.3.0
1204
		 *
1205
		 * @param bool $enabled Should Related Posts be enabled on the current page.
1206
		 */
1207
		return apply_filters( 'jetpack_relatedposts_filter_enabled_for_request', $enabled );
1208
	}
1209
1210
	/**
1211
	 * Adds filters and enqueues assets.
1212
	 *
1213
	 * @uses self::_enqueue_assets, self::_setup_shortcode, add_filter
1214
	 * @return null
1215
	 */
1216
	protected function _action_frontend_init_page() {
1217
		$this->_enqueue_assets( true, true );
1218
		$this->_setup_shortcode();
1219
1220
		add_filter( 'the_content', array( $this, 'filter_add_target_to_dom' ), 40 );
1221
	}
1222
1223
	/**
1224
	 * Enqueues assets needed to do async loading of related posts.
1225
	 *
1226
	 * @uses wp_enqueue_script, wp_enqueue_style, plugins_url
1227
	 * @return null
1228
	 */
1229
	protected function _enqueue_assets( $script, $style ) {
1230
		if ( $script ) {
1231
			wp_enqueue_script( 'jetpack_related-posts', plugins_url( 'related-posts.js', __FILE__ ), array( 'jquery' ), self::VERSION );
1232
			$related_posts_js_options = array(
1233
				/**
1234
				 * Filter each Related Post Heading structure.
1235
				 *
1236
				 * @since 4.0.0
1237
				 *
1238
				 * @param string $str Related Post Heading structure. Default to h4.
1239
				 */
1240
				'post_heading' => apply_filters( 'jetpack_relatedposts_filter_post_heading', esc_attr( 'h4' ) ),
1241
			);
1242
			wp_localize_script( 'jetpack_related-posts', 'related_posts_js_options', $related_posts_js_options );
1243
		}
1244
		if ( $style ){
1245
			if( is_rtl() ) {
1246
				wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'rtl/related-posts-rtl.css', __FILE__ ), array(), self::VERSION );
1247
			} else {
1248
				wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'related-posts.css', __FILE__ ), array(), self::VERSION );
1249
			}
1250
		}
1251
	}
1252
1253
	/**
1254
	 * Sets up the shortcode processing.
1255
	 *
1256
	 * @uses add_filter, add_shortcode
1257
	 * @return null
1258
	 */
1259
	protected function _setup_shortcode() {
1260
		add_filter( 'the_content', array( $this, 'test_for_shortcode' ), 0 );
1261
1262
		add_shortcode( self::SHORTCODE, array( $this, 'get_target_html' ) );
1263
	}
1264
1265
	protected function _allow_feature_toggle() {
1266
		if ( null === $this->_allow_feature_toggle ) {
1267
			/**
1268
			 * Filter the display of the Related Posts toggle in Settings > Reading.
1269
			 *
1270
			 * @module related-posts
1271
			 *
1272
			 * @since 2.8.0
1273
			 *
1274
			 * @param bool false Display a feature toggle. Default to false.
1275
			 */
1276
			$this->_allow_feature_toggle = apply_filters( 'jetpack_relatedposts_filter_allow_feature_toggle', false );
1277
		}
1278
		return $this->_allow_feature_toggle;
1279
	}
1280
}
1281
1282
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...
1283
	protected $_query_name;
1284
1285
	/**
1286
	 * Allows callers of this class to tag each query with a unique name for tracking purposes.
1287
	 *
1288
	 * @param string $name
1289
	 * @return Jetpack_RelatedPosts_Raw
1290
	 */
1291
	public function set_query_name( $name ) {
1292
		$this->_query_name = (string) $name;
1293
		return $this;
1294
	}
1295
1296
	/**
1297
	 * The raw related posts class can be used by other plugins or themes
1298
	 * to get related content. This class wraps the existing RelatedPosts
1299
	 * logic thus we never want to add anything to the DOM or do anything
1300
	 * for event hooks. We will also not present any settings for this
1301
	 * class and keep it enabled as calls to this class is done
1302
	 * programmatically.
1303
	 */
1304
	public function action_admin_init() {}
1305
	public function action_frontend_init() {}
1306
	public function get_options() {
1307
		return array(
1308
			'enabled' => true,
1309
		);
1310
	}
1311
1312
	/**
1313
	 * Workhorse method to return array of related posts ids matched by ElasticSearch.
1314
	 *
1315
	 * @param int $post_id
1316
	 * @param int $size
1317
	 * @param array $filters
1318
	 * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body
1319
	 * @return array
1320
	 */
1321
	protected function _get_related_posts( $post_id, $size, array $filters ) {
1322
		$hits = $this->_filter_non_public_posts(
1323
			$this->_get_related_post_ids(
1324
				$post_id,
1325
				$size,
1326
				$filters
1327
			)
1328
		);
1329
1330
		/** This filter is already documented in modules/related-posts/related-posts.php */
1331
		$hits = apply_filters( 'jetpack_relatedposts_filter_hits', $hits, $post_id );
1332
1333
		return $hits;
1334
	}
1335
}
1336