Completed
Push — sync/2may2017-related-posts ( 11e680 )
by George
09:40
created

_get_auto_citation_posts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
class Jetpack_RelatedPosts {
3
	const VERSION = '20170109';
4
	const SHORTCODE = 'jetpack-related-posts';
5
	private static $instance = null;
6
	private static $instance_raw = null;
7
8
	/**
9
	 * Creates and returns a static instance of Jetpack_RelatedPosts.
10
	 *
11
	 * @return Jetpack_RelatedPosts
12
	 */
13 View Code Duplication
	public static function init() {
14
		if ( ! self::$instance ) {
15
			if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init' ) ) {
16
				self::$instance = WPCOM_RelatedPosts::init();
17
			} else {
18
				self::$instance = new Jetpack_RelatedPosts(
19
					get_current_blog_id(),
20
					Jetpack_Options::get_option( 'id' )
21
				);
22
			}
23
		}
24
25
		return self::$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
		if ( ! self::$instance_raw ) {
35
			if ( class_exists('WPCOM_RelatedPosts') && method_exists( 'WPCOM_RelatedPosts', 'init_raw' ) ) {
36
				self::$instance_raw = WPCOM_RelatedPosts::init_raw();
37
			} else {
38
				self::$instance_raw = new Jetpack_RelatedPosts_Raw(
39
					get_current_blog_id(),
40
					Jetpack_Options::get_option( 'id' )
41
				);
42
			}
43
		}
44
45
		return self::$instance_raw;
46
	}
47
48
	protected $_blog_id_local;
49
	protected $_blog_id_wpcom;
50
	protected $_options;
51
	protected $_allow_feature_toggle;
52
	protected $_blog_charset;
53
	protected $_convert_charset;
54
	protected $_previous_post_id;
55
	protected $_found_shortcode = false;
56
	protected $_citations_enabled = false;
57
58
	/**
59
	 * Constructor for Jetpack_RelatedPosts.
60
	 *
61
	 * @param int $blog_id_local
62
	 * @param int $blog_id_wpcom
63
	 * @uses get_option, add_action, apply_filters
64
	 * @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...
65
	 */
66
	public function __construct( $blog_id_local, $blog_id_wpcom ) {
67
		$this->_blog_id_local = $blog_id_local;
68
		$this->_blog_id_wpcom = $blog_id_wpcom;
69
		$this->_blog_charset = get_option( 'blog_charset' );
70
		$this->_convert_charset = ( function_exists( 'iconv' ) && ! preg_match( '/^utf\-?8$/i', $this->_blog_charset ) );
71
72
		add_action( 'admin_init', array( $this, 'action_admin_init' ) );
73
		add_action( 'wp', array( $this, 'action_frontend_init' ) );
74
75
		if ( ! class_exists( 'Jetpack_Media_Summary' ) ) {
76
			jetpack_require_lib( 'class.media-summary' );
77
		}
78
79
		// Add Related Posts to the REST API Post response.
80
		if ( function_exists( 'register_rest_field' ) ) {
81
			add_action( 'rest_api_init',  array( $this, 'rest_register_related_posts' ) );
82
		}
83
	}
84
85
	protected function set_citations_enabled() {
86
		//disable, some bugs causing query parsing errors
87
		return;
88
		if ( ! is_automattician() )
0 ignored issues
show
Unused Code introduced by
if (!is_automattician()) { return; } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
89
			return;
90
		$whitelist = array(
91
			56857843, //elasticsearchp2
92
			14838835, //datap2
93
			86187505, //readersquadp2
94
		);
95
96
		$_blog_id = get_current_blog_id();
97
		if ( in_array( $_blog_id, $whitelist ) )
98
			$this->_citations_enabled = true;
99
		else
100
			$this->_citations_enabled = false;
101
	}
102
103
	/**
104
	 * =================
105
	 * ACTIONS & FILTERS
106
	 * =================
107
	 */
108
109
	/**
110
	 * Add a checkbox field to Settings > Reading for enabling related posts.
111
	 *
112
	 * @action admin_init
113
	 * @uses add_settings_field, __, register_setting, add_action
114
	 * @return null
115
	 */
116
	public function action_admin_init() {
117
118
		// Add the setting field [jetpack_relatedposts] and place it in Settings > Reading
119
		add_settings_field( 'jetpack_relatedposts', '<span id="jetpack_relatedposts">' . __( 'Related posts', 'jetpack' ) . '</span>', array( $this, 'print_setting_html' ), 'reading' );
120
		register_setting( 'reading', 'jetpack_relatedposts', array( $this, 'parse_options' ) );
121
		add_action('admin_head', array( $this, 'print_setting_head' ) );
122
123
		if( 'options-reading.php' == $GLOBALS['pagenow'] ) {
124
			// Enqueue style for live preview on the reading settings page
125
			$this->_enqueue_assets( false, true );
126
		}
127
	}
128
129
	/**
130
	 * Load related posts assets if it's a elegiable front end page or execute search and return JSON if it's an endpoint request.
131
	 *
132
	 * @global $_GET
133
	 * @action wp
134
	 * @uses add_shortcode, get_the_ID
135
	 * @returns null
136
	 */
137
	public function action_frontend_init() {
138
		$this->set_citations_enabled();
139
		// Add a shortcode handler that outputs nothing, this gets overridden later if we can display related content
140
		add_shortcode( self::SHORTCODE, array( $this, 'get_target_html_unsupported' ) );
141
142
		if ( ! $this->_enabled_for_request() )
143
			return;
144
145
		if ( isset( $_GET['relatedposts'] ) ) {
146
			$excludes = array();
147
			if ( isset( $_GET['relatedposts_exclude'] ) ) {
148
				if ( is_string( $_GET['relatedposts_exclude'] ) ) {
149
					$excludes = explode( ',', $_GET['relatedposts_exclude'] );
150
				} elseif ( is_array( $_GET['relatedposts_exclude'] ) ) {
151
					$excludes = array_values( $_GET['relatedposts_exclude'] );
152
				}
153
154
				$excludes = array_unique( array_filter( array_map( 'absint', $excludes ) ) );
155
			}
156
157
			$this->_action_frontend_init_ajax( $excludes );
158
		} else {
159
			if ( isset( $_GET['relatedposts_hit'], $_GET['relatedposts_origin'], $_GET['relatedposts_position'] ) ) {
160
				$this->_log_click( $_GET['relatedposts_origin'], get_the_ID(), $_GET['relatedposts_position'] );
161
				$this->_previous_post_id = (int) $_GET['relatedposts_origin'];
162
			}
163
164
			$this->_action_frontend_init_page();
165
		}
166
167
	}
168
169
	/**
170
	 * Render insertion point.
171
	 *
172
	 * @since 4.2.0
173
	 *
174
	 * @return string
175
	 */
176
	public function get_headline() {
177
		$options = $this->get_options();
178
179
		if ( $options['show_headline'] ) {
180
			if ( $this->_citations_enabled ) {
181
				$options['headline'] = __( 'Potential Citations', 'jetpack' );
182
			}
183
			$headline = sprintf(
184
				/** This filter is already documented in modules/sharedaddy/sharing-service.php */
185
				apply_filters( 'jetpack_sharing_headline_html', '<h3 class="jp-relatedposts-headline"><em>%s</em></h3>', esc_html( $options['headline'] ), 'related-posts' ),
186
				esc_html( $options['headline'] )
187
			);
188
		} else {
189
			$headline = '';
190
		}
191
		return $headline;
192
	}
193
194
	/**
195
	 * Adds a target to the post content to load related posts into if a shortcode for it did not already exist.
196
	 *
197
	 * @filter the_content
198
	 * @param string $content
199
	 * @returns string
200
	 */
201
	public function filter_add_target_to_dom( $content ) {
202
		if ( !$this->_found_shortcode ) {
203
			$content .= "\n" . $this->get_target_html();
204
		}
205
206
		return $content;
207
	}
208
209
	/**
210
	 * Looks for our shortcode on the unfiltered content, this has to execute early.
211
	 *
212
	 * @filter the_content
213
	 * @param string $content
214
	 * @uses has_shortcode
215
	 * @returns string
216
	 */
217
	public function test_for_shortcode( $content ) {
218
		$this->_found_shortcode = has_shortcode( $content, self::SHORTCODE );
219
220
		return $content;
221
	}
222
223
	/**
224
	 * Returns the HTML for the related posts section.
225
	 *
226
	 * @uses esc_html__, apply_filters
227
	 * @returns string
228
	 */
229
	public function get_target_html() {
230
		require_once JETPACK__PLUGIN_DIR . '/sync/class.jetpack-sync-settings.php';
231
		if ( Jetpack_Sync_Settings::is_syncing() ) {
232
			return '';
233
		}
234
235
		/**
236
		 * Filter the Related Posts headline.
237
		 *
238
		 * @module related-posts
239
		 *
240
		 * @since 3.0.0
241
		 *
242
		 * @param string $headline Related Posts heading.
243
		 */
244
		$headline = apply_filters( 'jetpack_relatedposts_filter_headline', $this->get_headline() );
245
246
		if ( $this->_previous_post_id ) {
247
			$exclude = "data-exclude='{$this->_previous_post_id}'";
248
		} else {
249
			$exclude = "";
250
		}
251
252
		return <<<EOT
253
<div id='jp-relatedposts' class='jp-relatedposts' $exclude>
254
	$headline
255
</div>
256
EOT;
257
	}
258
259
	/**
260
	 * 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.
261
	 *
262
	 * @returns string
263
	 */
264
	public function get_target_html_unsupported() {
265
		require_once JETPACK__PLUGIN_DIR . '/sync/class.jetpack-sync-settings.php';
266
		if ( Jetpack_Sync_Settings::is_syncing() ) {
267
			return '';
268
		}
269
		return "\n\n<!-- Jetpack Related Posts is not supported in this context. -->\n\n";
270
	}
271
272
	/**
273
	 * ========================
274
	 * PUBLIC UTILITY FUNCTIONS
275
	 * ========================
276
	 */
277
278
	/**
279
	 * Gets options set for Jetpack_RelatedPosts and merge with defaults.
280
	 *
281
	 * @uses Jetpack_Options::get_option, apply_filters
282
	 * @return array
283
	 */
284
	public function get_options() {
285
		if ( null === $this->_options ) {
286
			$this->_options = Jetpack_Options::get_option( 'relatedposts', array() );
287
			if ( ! is_array( $this->_options ) )
288
				$this->_options = array();
289
			if ( ! isset( $this->_options['enabled'] ) )
290
				$this->_options['enabled'] = true;
291
			if ( ! isset( $this->_options['show_headline'] ) )
292
				$this->_options['show_headline'] = true;
293
			if ( ! isset( $this->_options['show_thumbnails'] ) )
294
				$this->_options['show_thumbnails'] = false;
295
			if ( ! isset( $this->_options['show_date'] ) ) {
296
				$this->_options['show_date'] = true;
297
			}
298
			if ( ! isset( $this->_options['show_context'] ) ) {
299
				$this->_options['show_context'] = true;
300
			}
301
			if ( ! isset( $this->_options['layout'] ) ) {
302
				$this->_options['layout'] = 'grid';
303
			}
304
			if ( ! isset( $this->_options['headline'] ) ) {
305
				$this->_options['headline'] = esc_html__( 'Related', 'jetpack' );
306
			}
307
			if ( empty( $this->_options['size'] ) || (int)$this->_options['size'] < 1 ) {
308
				if ( $this->_citations_enabled )
309
					$this->_options['size'] = 12;
310
				else
311
					$this->_options['size'] = 3;
312
			}
313
314
			/**
315
			 * Filter Related Posts basic options.
316
			 *
317
			 * @module related-posts
318
			 *
319
			 * @since 2.8.0
320
			 *
321
			 * @param array $this->_options Array of basic Related Posts options.
322
			 */
323
			$this->_options = apply_filters( 'jetpack_relatedposts_filter_options', $this->_options );
324
		}
325
326
		return $this->_options;
327
	}
328
329
	public function get_option( $option_name ) {
330
		$options = $this->get_options();
331
332
		if ( isset( $options[ $option_name ] ) ) {
333
			return $options[ $option_name ];
334
		}
335
336
		return false;
337
	}
338
339
	/**
340
	 * Parses input and returns normalized options array.
341
	 *
342
	 * @param array $input
343
	 * @uses self::get_options
344
	 * @return array
345
	 */
346
	public function parse_options( $input ) {
347
		$current = $this->get_options();
348
349
		if ( !is_array( $input ) )
350
			$input = array();
351
352
		if (
353
			! isset( $input['enabled'] )
354
			|| isset( $input['show_date'] )
355
			|| isset( $input['show_context'] )
356
			|| isset( $input['layout'] )
357
			|| isset( $input['headline'] )
358
			) {
359
			$input['enabled'] = '1';
360
		}
361
362
		if ( '1' == $input['enabled'] ) {
363
			$current['enabled'] = true;
364
			$current['show_headline'] = ( isset( $input['show_headline'] ) && '1' == $input['show_headline'] );
365
			$current['show_thumbnails'] = ( isset( $input['show_thumbnails'] ) && '1' == $input['show_thumbnails'] );
366
			$current['show_date'] = ( isset( $input['show_date'] ) && '1' == $input['show_date'] );
367
			$current['show_context'] = ( isset( $input['show_context'] ) && '1' == $input['show_context'] );
368
			$current['layout'] = isset( $input['layout'] ) && in_array( $input['layout'], array( 'grid', 'list' ), true ) ? $input['layout'] : 'grid';
369
			$current['headline'] = isset( $input['headline'] ) ? $input['headline'] : esc_html__( 'Related', 'jetpack' );
370
		} else {
371
			$current['enabled'] = false;
372
		}
373
374
		if ( isset( $input['size'] ) && (int)$input['size'] > 0 )
375
			$current['size'] = (int)$input['size'];
376
		else
377
			$current['size'] = null;
378
379
		return $current;
380
	}
381
382
	/**
383
	 * HTML for admin settings page.
384
	 *
385
	 * @uses self::get_options, checked, esc_html__
386
	 * @returns null
387
	 */
388
	public function print_setting_html() {
389
		$options = $this->get_options();
390
391
		$ui_settings_template = <<<EOT
392
<ul id="settings-reading-relatedposts-customize">
393
	<li>
394
		<label><input name="jetpack_relatedposts[show_headline]" type="checkbox" value="1" %s /> %s</label>
395
	</li>
396
	<li>
397
		<label><input name="jetpack_relatedposts[show_thumbnails]" type="checkbox" value="1" %s /> %s</label>
398
	</li>
399
	<li>
400
		<label><input name="jetpack_relatedposts[show_date]" type="checkbox" value="1" %s /> %s</label>
401
	</li>
402
	<li>
403
		<label><input name="jetpack_relatedposts[show_context]" type="checkbox" value="1" %s /> %s</label>
404
	</li>
405
</ul>
406
<div id='settings-reading-relatedposts-preview'>
407
	%s
408
	<div id="jp-relatedposts" class="jp-relatedposts"></div>
409
</div>
410
EOT;
411
		$ui_settings = sprintf(
412
			$ui_settings_template,
413
			checked( $options['show_headline'], true, false ),
414
			esc_html__( 'Show a "Related" header to more clearly separate the related section from posts', 'jetpack' ),
415
			checked( $options['show_thumbnails'], true, false ),
416
			esc_html__( 'Use a large and visually striking layout', 'jetpack' ),
417
			checked( $options['show_date'], true, false ),
418
			esc_html__( 'Show entry date', 'jetpack' ),
419
			checked( $options['show_context'], true, false ),
420
			esc_html__( 'Show context (category or tag)', 'jetpack' ),
421
			esc_html__( 'Preview:', 'jetpack' )
422
		);
423
424
		if ( !$this->_allow_feature_toggle() ) {
425
			$template = <<<EOT
426
<input type="hidden" name="jetpack_relatedposts[enabled]" value="1" />
427
%s
428
EOT;
429
			printf(
430
				$template,
431
				$ui_settings
432
			);
433
		} else {
434
			$template = <<<EOT
435
<ul id="settings-reading-relatedposts">
436
	<li>
437
		<label><input type="radio" name="jetpack_relatedposts[enabled]" value="0" class="tog" %s /> %s</label>
438
	</li>
439
	<li>
440
		<label><input type="radio" name="jetpack_relatedposts[enabled]" value="1" class="tog" %s /> %s</label>
441
		%s
442
	</li>
443
</ul>
444
EOT;
445
			printf(
446
				$template,
447
				checked( $options['enabled'], false, false ),
448
				esc_html__( 'Hide related content after posts', 'jetpack' ),
449
				checked( $options['enabled'], true, false ),
450
				esc_html__( 'Show related content after posts', 'jetpack' ),
451
				$ui_settings
452
			);
453
		}
454
	}
455
456
	/**
457
	 * Head JS/CSS for admin settings page.
458
	 *
459
	 * @uses esc_html__
460
	 * @returns null
461
	 */
462
	public function print_setting_head() {
463
464
		// only dislay the Related Posts JavaScript on the Reading Settings Admin Page
465
		$current_screen =  get_current_screen();
466
467
		if ( is_null( $current_screen ) ) {
468
			return;
469
		}
470
471
		if( 'options-reading' != $current_screen->id )
472
			return;
473
474
		$related_headline = sprintf(
475
			'<h3 class="jp-relatedposts-headline"><em>%s</em></h3>',
476
			esc_html__( 'Related', 'jetpack' )
477
		);
478
479
		$href_params = 'class="jp-relatedposts-post-a" href="#jetpack_relatedposts" rel="nofollow" data-origin="0" data-position="0"';
480
		$related_with_images = <<<EOT
481
<div class="jp-relatedposts-items jp-relatedposts-items-visual">
482
	<div class="jp-relatedposts-post jp-relatedposts-post0 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
483
		<a $href_params>
484
			<img class="jp-relatedposts-post-img" src="https://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">
485
		</a>
486
		<h4 class="jp-relatedposts-post-title">
487
			<a $href_params>Big iPhone/iPad Update Now Available</a>
488
		</h4>
489
		<p class="jp-relatedposts-post-excerpt">Big iPhone/iPad Update Now Available</p>
490
		<p class="jp-relatedposts-post-context">In "Mobile"</p>
491
	</div>
492
	<div class="jp-relatedposts-post jp-relatedposts-post1 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
493
		<a $href_params>
494
			<img class="jp-relatedposts-post-img" src="https://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">
495
		</a>
496
		<h4 class="jp-relatedposts-post-title">
497
			<a $href_params>The WordPress for Android App Gets a Big Facelift</a>
498
		</h4>
499
		<p class="jp-relatedposts-post-excerpt">The WordPress for Android App Gets a Big Facelift</p>
500
		<p class="jp-relatedposts-post-context">In "Mobile"</p>
501
	</div>
502
	<div class="jp-relatedposts-post jp-relatedposts-post2 jp-relatedposts-post-thumbs" data-post-id="0" data-post-format="image">
503
		<a $href_params>
504
			<img class="jp-relatedposts-post-img" src="https://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">
505
		</a>
506
		<h4 class="jp-relatedposts-post-title">
507
			<a $href_params>Upgrade Focus: VideoPress For Weddings</a>
508
		</h4>
509
		<p class="jp-relatedposts-post-excerpt">Upgrade Focus: VideoPress For Weddings</p>
510
		<p class="jp-relatedposts-post-context">In "Upgrade"</p>
511
	</div>
512
</div>
513
EOT;
514
		$related_with_images = str_replace( "\n", '', $related_with_images );
515
		$related_without_images = <<<EOT
516
<div class="jp-relatedposts-items jp-relatedposts-items-minimal">
517
	<p class="jp-relatedposts-post jp-relatedposts-post0" data-post-id="0" data-post-format="image">
518
		<span class="jp-relatedposts-post-title"><a $href_params>Big iPhone/iPad Update Now Available</a></span>
519
		<span class="jp-relatedposts-post-context">In "Mobile"</span>
520
	</p>
521
	<p class="jp-relatedposts-post jp-relatedposts-post1" data-post-id="0" data-post-format="image">
522
		<span class="jp-relatedposts-post-title"><a $href_params>The WordPress for Android App Gets a Big Facelift</a></span>
523
		<span class="jp-relatedposts-post-context">In "Mobile"</span>
524
	</p>
525
	<p class="jp-relatedposts-post jp-relatedposts-post2" data-post-id="0" data-post-format="image">
526
		<span class="jp-relatedposts-post-title"><a $href_params>Upgrade Focus: VideoPress For Weddings</a></span>
527
		<span class="jp-relatedposts-post-context">In "Upgrade"</span>
528
	</p>
529
</div>
530
EOT;
531
		$related_without_images = str_replace( "\n", '', $related_without_images );
532
533
		if ( $this->_allow_feature_toggle() ) {
534
			$extra_css = '#settings-reading-relatedposts-customize { padding-left:2em; margin-top:.5em; }';
535
		} else {
536
			$extra_css = '';
537
		}
538
539
		echo <<<EOT
540
<style type="text/css">
541
	#settings-reading-relatedposts .disabled { opacity:.5; filter:Alpha(opacity=50); }
542
	#settings-reading-relatedposts-preview .jp-relatedposts { background:#fff; padding:.5em; width:75%; }
543
	$extra_css
544
</style>
545
<script type="text/javascript">
546
	jQuery( document ).ready( function($) {
547
		var update_ui = function() {
548
			var is_enabled = true;
549
			if ( 'radio' == $( 'input[name="jetpack_relatedposts[enabled]"]' ).attr('type') ) {
550
				if ( '0' == $( 'input[name="jetpack_relatedposts[enabled]"]:checked' ).val() ) {
551
					is_enabled = false;
552
				}
553
			}
554
			if ( is_enabled ) {
555
				$( '#settings-reading-relatedposts-customize' )
556
					.removeClass( 'disabled' )
557
					.find( 'input' )
558
					.attr( 'disabled', false );
559
				$( '#settings-reading-relatedposts-preview' )
560
					.removeClass( 'disabled' );
561
			} else {
562
				$( '#settings-reading-relatedposts-customize' )
563
					.addClass( 'disabled' )
564
					.find( 'input' )
565
					.attr( 'disabled', true );
566
				$( '#settings-reading-relatedposts-preview' )
567
					.addClass( 'disabled' );
568
			}
569
		};
570
571
		var update_preview = function() {
572
			var html = '';
573
			if ( $( 'input[name="jetpack_relatedposts[show_headline]"]:checked' ).length ) {
574
				html += '$related_headline';
575
			}
576
			if ( $( 'input[name="jetpack_relatedposts[show_thumbnails]"]:checked' ).length ) {
577
				html += '$related_with_images';
578
			} else {
579
				html += '$related_without_images';
580
			}
581
			$( '#settings-reading-relatedposts-preview .jp-relatedposts' ).html( html );
582
			if ( $( 'input[name="jetpack_relatedposts[show_date]"]:checked' ).length ) {
583
				$( '.jp-relatedposts-post-title' ).each( function() {
584
					$( this ).after( $( '<span>August 8, 2005</span>' ) );
585
				} );
586
			}
587
			if ( $( 'input[name="jetpack_relatedposts[show_context]"]:checked' ).length ) {
588
				$( '.jp-relatedposts-post-context' ).show();
589
			} else {
590
				$( '.jp-relatedposts-post-context' ).hide();
591
			}
592
			$( '#settings-reading-relatedposts-preview .jp-relatedposts' ).show();
593
		};
594
595
		// Update on load
596
		update_preview();
597
		update_ui();
598
599
		// Update on change
600
		$( '#settings-reading-relatedposts-customize input' )
601
			.change( update_preview );
602
		$( '#settings-reading-relatedposts' )
603
			.find( 'input.tog' )
604
			.change( update_ui );
605
	});
606
</script>
607
EOT;
608
	}
609
610
	/**
611
	 * Gets an array of related posts that match the given post_id.
612
	 *
613
	 * @param int $post_id
614
	 * @param array $args - params to use when building ElasticSearch filters to narrow down the search domain.
615
	 * @uses self::get_options, get_post_type, wp_parse_args, apply_filters
616
	 * @return array
617
	 */
618
	public function get_for_post_id( $post_id, array $args ) {
619
		$options = $this->get_options();
620
621
		if ( ! empty( $args['size'] ) )
622
			$options['size'] = $args['size'];
623
624
		if ( ! $options['enabled'] || 0 == (int)$post_id || empty( $options['size'] ) )
625
			return array();
626
627
		$defaults = array(
628
			'size' => (int)$options['size'],
629
			'post_type' => get_post_type( $post_id ),
630
			'post_formats' => array(),
631
			'has_terms' => array(),
632
			'date_range' => array(),
633
			'exclude_post_ids' => array(),
634
		);
635
		$args = wp_parse_args( $args, $defaults );
636
		/**
637
		 * Filter the arguments used to retrieve a list of Related Posts.
638
		 *
639
		 * @module related-posts
640
		 *
641
		 * @since 2.8.0
642
		 *
643
		 * @param array $args Array of options to retrieve Related Posts.
644
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
645
		 */
646
		$args = apply_filters( 'jetpack_relatedposts_filter_args', $args, $post_id );
647
648
		$filters = $this->_get_es_filters_from_args( $post_id, $args );
649
		/**
650
		 * Filter ElasticSearch options used to calculate Related Posts.
651
		 *
652
		 * @module related-posts
653
		 *
654
		 * @since 2.8.0
655
		 *
656
		 * @param array $filters Array of ElasticSearch filters based on the post_id and args.
657
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
658
		 */
659
		$filters = apply_filters( 'jetpack_relatedposts_filter_filters', $filters, $post_id );
660
661
		$results = $this->_get_related_posts( $post_id, $args['size'], $filters );
662
		/**
663
		 * Filter the array of related posts matched by ElasticSearch.
664
		 *
665
		 * @module related-posts
666
		 *
667
		 * @since 2.8.0
668
		 *
669
		 * @param array $results Array of related posts matched by ElasticSearch.
670
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
671
		 */
672
		return apply_filters( 'jetpack_relatedposts_returned_results', $results, $post_id );
673
	}
674
675
	/**
676
	 * Gets an array of auto citations for the given post_id.
677
	 *
678
	 * @param int $post_id
679
	 * @param array $args - params to use when building ElasticSearch filters to narrow down the search domain.
680
	 * @uses get_options, wp_parse_args, apply_filters
681
	 * @return array
682
	 */
683
	public function get_auto_citation_posts( $post_id, array $args ) {
684
		$options = $this->get_options();
685
		if ( ! $options['enabled'] || 0 == (int)$post_id )
686
			return array();
687
688
		$defaults = array(
689
			'size' => 12,
690
			'date_range' => array(),
691
			'seed' => mt_rand( 0, 10 ), //auto citations should change
692
		);
693
		$args = wp_parse_args( $args, $defaults );
694
695
		$filters = array();
696
697
		$results = $this->_get_auto_citation_posts( $post_id, $args['size'], $filters );
0 ignored issues
show
Bug introduced by
The method _get_auto_citation_posts() does not exist on Jetpack_RelatedPosts. Did you maybe mean get_auto_citation_posts()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
698
699
		$posts = array();
700
		foreach( $results as $i => $item )
701
			$posts[] = $this->_get_autocite_post_data_for_post( $item, $i, $post_id );
702
703
		return $posts;
704
	}
705
706
707
	/**
708
	 * Returns a UTF-8 encoded array of post information for the given post_id
709
	 *
710
	 * @param int $post_id
0 ignored issues
show
Bug introduced by
There is no parameter named $post_id. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
711
	 * @param int $position
712
	 * @param int $origin The post id that this is related to
713
	 * @uses get_post, get_permalink, remove_query_arg, get_post_format, apply_filters
714
	 * @return array
715
	 */
716
	protected function _get_autocite_post_data_for_post( $item, $position, $origin ) {
717
		switch_to_blog( $item['blog_id'] );
718
719
		$post = get_post( $item['post_id'] );
720
721
		$data = array(
722
			'id' => $post->ID,
723
			'url' => get_permalink( $post->ID ),
724
			'url_meta' => array( 'origin' => $origin, 'position' => $position ),
725
			'title' => $this->_to_utf8( $this->_get_title( $post->post_title, $post->post_content ) ),
726
			'date' => get_the_date( '', $post->ID ),
727
			'format' => get_post_format( $post->ID ),
728
			'excerpt' => $this->_to_utf8( $this->_get_excerpt( $post->post_excerpt, $post->post_content ) ),
729
			'rel' => 'nofollow',
730
			'context' => $item['context'],
731
			'img' => '',
732
		);
733
734
		restore_current_blog();
735
		return $data;
736
	}
737
738
739
	/**
740
	 * =========================
741
	 * PRIVATE UTILITY FUNCTIONS
742
	 * =========================
743
	 */
744
745
	/**
746
	 * Creates an array of ElasticSearch filters based on the post_id and args.
747
	 *
748
	 * @param int $post_id
749
	 * @param array $args
750
	 * @uses apply_filters, get_post_types, get_post_format_strings
751
	 * @return array
752
	 */
753
	protected function _get_es_filters_from_args( $post_id, array $args ) {
754
		$filters = array();
755
756
		/**
757
		 * Filter the terms used to search for Related Posts.
758
		 *
759
		 * @module related-posts
760
		 *
761
		 * @since 2.8.0
762
		 *
763
		 * @param array $args['has_terms'] Array of terms associated to the Related Posts.
764
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
765
		 */
766
		$args['has_terms'] = apply_filters( 'jetpack_relatedposts_filter_has_terms', $args['has_terms'], $post_id );
767
		if ( ! empty( $args['has_terms'] ) ) {
768
			foreach( (array)$args['has_terms'] as $term ) {
769
				if ( mb_strlen( $term->taxonomy ) ) {
770
					switch ( $term->taxonomy ) {
771
						case 'post_tag':
772
							$tax_fld = 'tag.slug';
773
							break;
774
						case 'category':
775
							$tax_fld = 'category.slug';
776
							break;
777
						default:
778
							$tax_fld = 'taxonomy.' . $term->taxonomy . '.slug';
779
							break;
780
					}
781
					$filters[] = array( 'term' => array( $tax_fld => $term->slug ) );
782
				}
783
			}
784
		}
785
786
		/**
787
		 * Filter the Post Types where we search Related Posts.
788
		 *
789
		 * @module related-posts
790
		 *
791
		 * @since 2.8.0
792
		 *
793
		 * @param array $args['post_type'] Array of Post Types.
794
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
795
		 */
796
		$args['post_type'] = apply_filters( 'jetpack_relatedposts_filter_post_type', $args['post_type'], $post_id );
797
		$valid_post_types = get_post_types();
798
		if ( is_array( $args['post_type'] ) ) {
799
			$sanitized_post_types = array();
800
			foreach ( $args['post_type'] as $pt ) {
801
				if ( in_array( $pt, $valid_post_types ) )
802
					$sanitized_post_types[] = $pt;
803
			}
804
			if ( ! empty( $sanitized_post_types ) )
805
				$filters[] = array( 'terms' => array( 'post_type' => $sanitized_post_types ) );
806
		} else if ( in_array( $args['post_type'], $valid_post_types ) && 'all' != $args['post_type'] ) {
807
			$filters[] = array( 'term' => array( 'post_type' => $args['post_type'] ) );
808
		}
809
810
		/**
811
		 * Filter the Post Formats where we search Related Posts.
812
		 *
813
		 * @module related-posts
814
		 *
815
		 * @since 3.3.0
816
		 *
817
		 * @param array $args['post_formats'] Array of Post Formats.
818
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
819
		 */
820
		$args['post_formats'] = apply_filters( 'jetpack_relatedposts_filter_post_formats', $args['post_formats'], $post_id );
821
		$valid_post_formats = get_post_format_strings();
822
		$sanitized_post_formats = array();
823
		foreach ( $args['post_formats'] as $pf ) {
824
			if ( array_key_exists( $pf, $valid_post_formats ) ) {
825
				$sanitized_post_formats[] = $pf;
826
			}
827
		}
828
		if ( ! empty( $sanitized_post_formats ) ) {
829
			$filters[] = array( 'terms' => array( 'post_format' => $sanitized_post_formats ) );
830
		}
831
832
		/**
833
		 * Filter the date range used to search Related Posts.
834
		 *
835
		 * @module related-posts
836
		 *
837
		 * @since 2.8.0
838
		 *
839
		 * @param array $args['date_range'] Array of a month interval where we search Related Posts.
840
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
841
		 */
842
		$args['date_range'] = apply_filters( 'jetpack_relatedposts_filter_date_range', $args['date_range'], $post_id );
843
		if ( is_array( $args['date_range'] ) && ! empty( $args['date_range'] ) ) {
844
			$args['date_range'] = array_map( 'intval', $args['date_range'] );
845
			if ( !empty( $args['date_range']['from'] ) && !empty( $args['date_range']['to'] ) ) {
846
				$filters[] = array(
847
					'range' => array(
848
						'date_gmt' => $this->_get_coalesced_range( $args['date_range'] ),
849
					)
850
				);
851
			}
852
		}
853
854
		/**
855
		 * Filter the Post IDs excluded from appearing in Related Posts.
856
		 *
857
		 * @module related-posts
858
		 *
859
		 * @since 2.9.0
860
		 *
861
		 * @param array $args['exclude_post_ids'] Array of Post IDs.
862
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
863
		 */
864
		$args['exclude_post_ids'] = apply_filters( 'jetpack_relatedposts_filter_exclude_post_ids', $args['exclude_post_ids'], $post_id );
865
		if ( !empty( $args['exclude_post_ids'] ) && is_array( $args['exclude_post_ids'] ) ) {
866
			foreach ( $args['exclude_post_ids'] as $exclude_post_id) {
867
				$exclude_post_id = (int)$exclude_post_id;
868
				$excluded_post_ids = array();
869
				if ( $exclude_post_id > 0 )
870
					$excluded_post_ids[] = $exclude_post_id;
871
			}
872
			$filters[] = array( 'not' => array( 'terms' => array( 'post_id' => $excluded_post_ids ) ) );
0 ignored issues
show
Bug introduced by
The variable $excluded_post_ids does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
873
		}
874
875
		return $filters;
876
	}
877
878
	/**
879
	 * Takes a range and coalesces it into a month interval bracketed by a time as determined by the blog_id to enhance caching.
880
	 *
881
	 * @param array $date_range
882
	 * @return array
883
	 */
884
	protected function _get_coalesced_range( array $date_range ) {
885
		$now = time();
886
		$coalesce_time = $this->_blog_id_wpcom % 86400;
887
		$current_time = $now - strtotime( 'today', $now );
888
889
		if ( $current_time < $coalesce_time && '01' == date( 'd', $now ) ) {
890
			// Move back 1 period
891
			return array(
892
				'from' => date( 'Y-m-01', strtotime( '-1 month', $date_range['from'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
893
				'to'   => date( 'Y-m-01', $date_range['to'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
894
			);
895
		} else {
896
			// Use current period
897
			return array(
898
				'from' => date( 'Y-m-01', $date_range['from'] ) . ' ' . date( 'H:i:s', $coalesce_time ),
899
				'to'   => date( 'Y-m-01', strtotime( '+1 month', $date_range['to'] ) ) . ' ' . date( 'H:i:s', $coalesce_time ),
900
			);
901
		}
902
	}
903
904
	/**
905
	 * Generate and output ajax response for related posts API call.
906
	 * NOTE: Calls exit() to end all further processing after payload has been outputed.
907
	 *
908
	 * @param array $excludes array of post_ids to exclude
909
	 * @uses send_nosniff_header, self::get_for_post_id, get_the_ID
910
	 * @return null
911
	 */
912
	protected function _action_frontend_init_ajax( array $excludes ) {
913
		define( 'DOING_AJAX', true );
914
915
		header( 'Content-type: application/json; charset=utf-8' ); // JSON can only be UTF-8
916
		send_nosniff_header();
917
918
		if ( $this->_citations_enabled ) {
919
			$related_posts = $this->get_auto_citation_posts( get_the_ID(), array() );
0 ignored issues
show
Unused Code introduced by
$related_posts is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
920
		} else {
921
			$related_posts = $this->get_for_post_id(
0 ignored issues
show
Unused Code introduced by
$related_posts is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
922
				get_the_ID(),
923
				array(
924
					'exclude_post_ids' => $excludes,
925
				)
926
			);
927
		}
928
929
		$options = $this->get_options();
930
931
		if ( isset( $_GET['jetpackrpcustomize'] ) ) {
932
933
			// If we're in the customizer, add dummy content.
934
			$date_now = current_time( get_option( 'date_format' ) );
935
			$related_posts = array(
936
				array(
937
					'id'       => - 1,
938
					'url'      => 'https://jetpackme.files.wordpress.com/2014/08/1-wpios-ipad-3-1-viewsite.png?w=350&h=200&crop=1',
939
					'url_meta' => array(
940
						'origin'   => 0,
941
						'position' => 0
942
					),
943
					'title'    => esc_html__( 'Big iPhone/iPad Update Now Available', 'jetpack' ),
944
					'date'     => $date_now,
945
					'format'   => false,
946
					'excerpt'  => esc_html__( 'It is that time of the year when devices are shiny again.', 'jetpack' ),
947
					'rel'      => 'nofollow',
948
					'context'  => esc_html__( 'In "Mobile"', 'jetpack' ),
949
					'img'      => array(
950
						'src'    => 'https://jetpackme.files.wordpress.com/2014/08/1-wpios-ipad-3-1-viewsite.png?w=350&h=200&crop=1',
951
						'width'  => 350,
952
						'height' => 200
953
					),
954
					'classes'  => array()
955
				),
956
				array(
957
					'id'       => - 1,
958
					'url'      => 'https://jetpackme.files.wordpress.com/2014/08/wordpress-com-news-wordpress-for-android-ui-update2.jpg?w=350&h=200&crop=1',
959
					'url_meta' => array(
960
						'origin'   => 0,
961
						'position' => 0
962
					),
963
					'title'    => esc_html__( 'The WordPress for Android App Gets a Big Facelift', 'jetpack' ),
964
					'date'     => $date_now,
965
					'format'   => false,
966
					'excerpt'  => esc_html__( 'Writing is new again in Android with the new WordPress app.', 'jetpack' ),
967
					'rel'      => 'nofollow',
968
					'context'  => esc_html__( 'In "Mobile"', 'jetpack' ),
969
					'img'      => array(
970
						'src'    => 'https://jetpackme.files.wordpress.com/2014/08/wordpress-com-news-wordpress-for-android-ui-update2.jpg?w=350&h=200&crop=1',
971
						'width'  => 350,
972
						'height' => 200
973
					),
974
					'classes'  => array()
975
				),
976
				array(
977
					'id'       => - 1,
978
					'url'      => 'https://jetpackme.files.wordpress.com/2014/08/videopresswedding.jpg?w=350&h=200&crop=1',
979
					'url_meta' => array(
980
						'origin'   => 0,
981
						'position' => 0
982
					),
983
					'title'    => esc_html__( 'Upgrade Focus, VideoPress for weddings', 'jetpack' ),
984
					'date'     => $date_now,
985
					'format'   => false,
986
					'excerpt'  => esc_html__( 'Weddings are in the spotlight now with VideoPress for weddings.', 'jetpack' ),
987
					'rel'      => 'nofollow',
988
					'context'  => esc_html__( 'In "Mobile"', 'jetpack' ),
989
					'img'      => array(
990
						'src'    => 'https://jetpackme.files.wordpress.com/2014/08/videopresswedding.jpg?w=350&h=200&crop=1',
991
						'width'  => 350,
992
						'height' => 200
993
					),
994
					'classes'  => array()
995
				),
996
			);
997
998
			for ( $total = 0; $total < $options['size'] - 3; $total++ ) {
999
				$related_posts[] = $related_posts[ $total ];
1000
			}
1001
1002
			$current_post = get_post();
1003
1004
			// Exclude current post after filtering to make sure it's excluded and not lost during filtering.
1005
			$excluded_posts = array_merge(
1006
				/** This filter is already documented in modules/related-posts/jetpack-related-posts.php */
1007
				apply_filters( 'jetpack_relatedposts_filter_exclude_post_ids', array() ),
1008
				array( $current_post->ID )
1009
			);
1010
1011
			// Fetch posts with featured image.
1012
			$with_post_thumbnails = get_posts( array(
1013
				'posts_per_page'   => $options['size'],
1014
				'post__not_in'     => $excluded_posts,
1015
				'post_type'        => $current_post->post_type,
1016
				'meta_key'         => '_thumbnail_id',
1017
				'suppress_filters' => false,
1018
			) );
1019
1020
			// If we don't have enough, fetch posts without featured image.
1021
			if ( 0 < ( $more = $options['size'] - count( $with_post_thumbnails ) ) ) {
1022
				$no_post_thumbnails = get_posts( array(
1023
					'posts_per_page'  => $more,
1024
					'post__not_in'    => $excluded_posts,
1025
					'post_type'       => $current_post->post_type,
1026
					'meta_query' => array(
1027
						array(
1028
							'key'     => '_thumbnail_id',
1029
							'compare' => 'NOT EXISTS',
1030
						),
1031
					),
1032
					'suppress_filters' => false,
1033
				) );
1034
			} else {
1035
				$no_post_thumbnails = array();
1036
			}
1037
1038
			foreach ( array_merge( $with_post_thumbnails, $no_post_thumbnails ) as $index => $real_post ) {
1039
				$related_posts[ $index ]['id']      = $real_post->ID;
1040
				$related_posts[ $index ]['url']     = esc_url( get_permalink( $real_post ) );
1041
				$related_posts[ $index ]['title']   = $this->_to_utf8( $this->_get_title( $real_post->post_title, $real_post->post_content ) );
1042
				$related_posts[ $index ]['date']    = get_the_date( '', $real_post );
1043
				$related_posts[ $index ]['excerpt'] = html_entity_decode( $this->_to_utf8( $this->_get_excerpt( $real_post->post_excerpt, $real_post->post_content ) ), ENT_QUOTES, 'UTF-8' );
1044
				$related_posts[ $index ]['img']     = $this->_generate_related_post_image_params( $real_post->ID );
1045
				$related_posts[ $index ]['context'] = $this->_generate_related_post_context( $real_post->ID );
1046
			}
1047
		} else {
1048
			$related_posts = $this->get_for_post_id(
1049
				get_the_ID(),
1050
				array(
1051
					'exclude_post_ids' => $excludes,
1052
				)
1053
			);
1054
		}
1055
1056
		$response = array(
1057
			'version' => self::VERSION,
1058
			'show_thumbnails' => (bool) $options['show_thumbnails'],
1059
			'show_date' => (bool) $options['show_date'],
1060
			'show_context' => (bool) $options['show_context'],
1061
			'layout' => (string) $options['layout'],
1062
			'headline' => (string) $options['headline'],
1063
			'items' => array(),
1064
		);
1065
1066
		if ( $this->_citations_enabled ) {
1067
			if ( count( $related_posts ) > 3 ) {
1068
				$i = 0;
1069
				foreach( $related_posts as $p ) {
1070
					$response['items'][$i][] = $p;
1071
					$i++;
1072
					if ( 3 == $i )
1073
						$i = 0;
1074
				}
1075
			}
1076
		} else {
1077
			if ( count( $related_posts ) == $options['size'] )
1078
				$response['items'] = $related_posts;
1079
		}
1080
1081
		echo json_encode( $response );
1082
1083
		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...
1084
	}
1085
1086
	/**
1087
	 * Returns a UTF-8 encoded array of post information for the given post_id
1088
	 *
1089
	 * @param int $post_id
1090
	 * @param int $position
1091
	 * @param int $origin The post id that this is related to
1092
	 * @uses get_post, get_permalink, remove_query_arg, get_post_format, apply_filters
1093
	 * @return array
1094
	 */
1095
	protected function _get_related_post_data_for_post( $post_id, $position, $origin ) {
1096
		$post = get_post( $post_id );
1097
1098
		return array(
1099
			'id' => $post->ID,
1100
			'url' => get_permalink( $post->ID ),
1101
			'url_meta' => array( 'origin' => $origin, 'position' => $position ),
1102
			'title' => $this->_to_utf8( $this->_get_title( $post->post_title, $post->post_content ) ),
1103
			'date' => get_the_date( '', $post->ID ),
1104
			'format' => get_post_format( $post->ID ),
1105
			'excerpt' => html_entity_decode( $this->_to_utf8( $this->_get_excerpt( $post->post_excerpt, $post->post_content ) ), ENT_QUOTES, 'UTF-8' ),
1106
			/**
1107
			 * Filters the rel attribute for the Related Posts' links.
1108
			 *
1109
			 * @module related-posts
1110
			 *
1111
			 * @since 3.7.0
1112
			 *
1113
			 * @param string nofollow Link rel attribute for Related Posts' link. Default is nofollow.
1114
			 * @param int $post->ID Post ID.
1115
			 */
1116
			'rel' => apply_filters( 'jetpack_relatedposts_filter_post_link_rel', 'nofollow', $post->ID ),
1117
			/**
1118
			 * Filter the context displayed below each Related Post.
1119
			 *
1120
			 * @module related-posts
1121
			 *
1122
			 * @since 3.0.0
1123
			 *
1124
			 * @param string $this->_to_utf8( $this->_generate_related_post_context( $post->ID ) ) Context displayed below each related post.
1125
			 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
1126
			 */
1127
			'context' => apply_filters(
1128
				'jetpack_relatedposts_filter_post_context',
1129
				$this->_to_utf8( $this->_generate_related_post_context( $post->ID ) ),
1130
				$post->ID
1131
			),
1132
			'img' => $this->_generate_related_post_image_params( $post->ID ),
1133
			/**
1134
			 * Filter the post css classes added on HTML markup.
1135
			 *
1136
			 * @module related-posts
1137
			 *
1138
			 * @since 3.8.0
1139
			 *
1140
			 * @param array array() CSS classes added on post HTML markup.
1141
			 * @param string $post_id Post ID.
1142
			 */
1143
			'classes' => apply_filters(
1144
				'jetpack_relatedposts_filter_post_css_classes',
1145
				array(),
1146
				$post->ID
1147
			),
1148
		);
1149
	}
1150
1151
	/**
1152
	 * Returns either the title or a small excerpt to use as title for post.
1153
	 *
1154
	 * @param string $post_title
1155
	 * @param string $post_content
1156
	 * @uses strip_shortcodes, wp_trim_words, __
1157
	 * @return string
1158
	 */
1159
	protected function _get_title( $post_title, $post_content ) {
1160
		if ( ! empty( $post_title ) ) {
1161
			return wp_strip_all_tags( $post_title );
1162
		}
1163
1164
		$post_title = wp_trim_words( wp_strip_all_tags( strip_shortcodes( $post_content ) ), 5, '…' );
1165
		if ( ! empty( $post_title ) ) {
1166
			return $post_title;
1167
		}
1168
1169
		return __( 'Untitled Post', 'jetpack' );
1170
	}
1171
1172
	/**
1173
	 * Returns a plain text post excerpt for title attribute of links.
1174
	 *
1175
	 * @param string $post_excerpt
1176
	 * @param string $post_content
1177
	 * @uses strip_shortcodes, wp_strip_all_tags, wp_trim_words
1178
	 * @return string
1179
	 */
1180
	protected function _get_excerpt( $post_excerpt, $post_content ) {
1181
		if ( empty( $post_excerpt ) )
1182
			$excerpt = $post_content;
1183
		else
1184
			$excerpt = $post_excerpt;
1185
1186
		return wp_trim_words( wp_strip_all_tags( strip_shortcodes( $excerpt ) ), 50, '…' );
1187
	}
1188
1189
	/**
1190
	 * Generates the thumbnail image to be used for the post. Uses the
1191
	 * image as returned by Jetpack_PostImages::get_image()
1192
	 *
1193
	 * @param int $post_id
1194
	 * @uses self::get_options, apply_filters, Jetpack_PostImages::get_image, Jetpack_PostImages::fit_image_url
1195
	 * @return string
1196
	 */
1197
	protected function _generate_related_post_image_params( $post_id ) {
1198
		$options = $this->get_options();
1199
		$image_params = array(
1200
			'src' => '',
1201
			'width' => 0,
1202
			'height' => 0,
1203
		);
1204
1205
		if ( ! $options['show_thumbnails'] ) {
1206
			return $image_params;
1207
		}
1208
1209
		/**
1210
		 * Filter the size of the Related Posts images.
1211
		 *
1212
		 * @module related-posts
1213
		 *
1214
		 * @since 2.8.0
1215
		 *
1216
		 * @param array array( 'width' => 350, 'height' => 200 ) Size of the images displayed below each Related Post.
1217
		 */
1218
		$thumbnail_size = apply_filters(
1219
			'jetpack_relatedposts_filter_thumbnail_size',
1220
			array( 'width' => 350, 'height' => 200 )
1221
		);
1222
		if ( !is_array( $thumbnail_size ) ) {
1223
			$thumbnail_size = array(
1224
				'width' => (int)$thumbnail_size,
1225
				'height' => (int)$thumbnail_size
1226
			);
1227
		}
1228
1229
		// Try to get post image
1230
		if ( class_exists( 'Jetpack_PostImages' ) ) {
1231
			$img_url = '';
1232
			$post_image = Jetpack_PostImages::get_image(
1233
				$post_id,
1234
				$thumbnail_size
1235
			);
1236
1237
			if ( is_array($post_image) ) {
1238
				$img_url = $post_image['src'];
1239
			} elseif ( class_exists( 'Jetpack_Media_Summary' ) ) {
1240
				$media = Jetpack_Media_Summary::get( $post_id );
1241
1242
				if ( is_array($media) && !empty( $media['image'] ) ) {
1243
					$img_url = $media['image'];
1244
				}
1245
			}
1246
1247
			if ( !empty( $img_url ) ) {
1248
				$image_params['width'] = $thumbnail_size['width'];
1249
				$image_params['height'] = $thumbnail_size['height'];
1250
				$image_params['src'] = Jetpack_PostImages::fit_image_url(
1251
					$img_url,
1252
					$thumbnail_size['width'],
1253
					$thumbnail_size['height']
1254
				);
1255
			}
1256
		}
1257
1258
		return $image_params;
1259
	}
1260
1261
	/**
1262
	 * Returns the string UTF-8 encoded
1263
	 *
1264
	 * @param string $text
1265
	 * @return string
1266
	 */
1267
	protected function _to_utf8( $text ) {
1268
		if ( $this->_convert_charset ) {
1269
			return iconv( $this->_blog_charset, 'UTF-8', $text );
1270
		} else {
1271
			return $text;
1272
		}
1273
	}
1274
1275
	/**
1276
	 * =============================================
1277
	 * PROTECTED UTILITY FUNCTIONS EXTENDED BY WPCOM
1278
	 * =============================================
1279
	 */
1280
1281
	/**
1282
	 * Workhorse method to return array of related posts matched by ElasticSearch.
1283
	 *
1284
	 * @param int $post_id
1285
	 * @param int $size
1286
	 * @param array $filters
1287
	 * @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
1288
	 * @return array
1289
	 */
1290
	protected function _get_related_posts( $post_id, $size, array $filters ) {
1291
		$hits = $this->_filter_non_public_posts(
1292
			$this->_get_related_post_ids(
1293
				$post_id,
1294
				$size,
1295
				$filters
1296
			)
1297
		);
1298
1299
		/**
1300
		 * Filter the Related Posts matched by ElasticSearch.
1301
		 *
1302
		 * @module related-posts
1303
		 *
1304
		 * @since 2.9.0
1305
		 *
1306
		 * @param array $hits Array of Post IDs matched by ElasticSearch.
1307
		 * @param string $post_id Post ID of the post for which we are retrieving Related Posts.
1308
		 */
1309
		$hits = apply_filters( 'jetpack_relatedposts_filter_hits', $hits, $post_id );
1310
1311
		$related_posts = array();
1312
		foreach ( $hits as $i => $hit ) {
1313
			$related_posts[] = $this->_get_related_post_data_for_post( $hit['id'], $i, $post_id );
1314
		}
1315
		return $related_posts;
1316
	}
1317
1318
	/**
1319
	 * Get array of related posts matched by ElasticSearch.
1320
	 *
1321
	 * @param int $post_id
1322
	 * @param int $size
1323
	 * @param array $filters
1324
	 * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body, get_post_meta, update_post_meta
1325
	 * @return array
1326
	 */
1327
	protected function _get_related_post_ids( $post_id, $size, array $filters ) {
1328
		$now_ts = time();
1329
		$cache_meta_key = '_jetpack_related_posts_cache';
1330
1331
		$body = array(
1332
			'size' => (int) $size,
1333
		);
1334
1335
		if ( !empty( $filters ) )
1336
			$body['filter'] = array( 'and' => $filters );
1337
1338
		// Build cache key
1339
		$cache_key = md5( serialize( $body ) );
1340
1341
		// Load all cached values
1342
		if ( wp_using_ext_object_cache() ) {
1343
			$transient_name = "{$cache_meta_key}_{$cache_key}_{$post_id}";
1344
			$cache = get_transient( $transient_name );
1345
			if ( false !== $cache ) {
1346
				return $cache;
1347
			}
1348
		} else {
1349
			$cache = get_post_meta( $post_id, $cache_meta_key, true );
1350
1351
			if ( empty( $cache ) )
1352
				$cache = array();
1353
1354
1355
			// Cache is valid! Return cached value.
1356
			if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) && $cache[ $cache_key ][ 'expires' ] > $now_ts ) {
1357
				return $cache[ $cache_key ][ 'payload' ];
1358
			}
1359
		}
1360
1361
		$response = wp_remote_post(
1362
			"https://public-api.wordpress.com/rest/v1/sites/{$this->_blog_id_wpcom}/posts/$post_id/related/",
1363
			array(
1364
				'timeout' => 10,
1365
				'user-agent' => 'jetpack_related_posts',
1366
				'sslverify' => true,
1367
				'body' => $body,
1368
			)
1369
		);
1370
1371
		// Oh no... return nothing don't cache errors.
1372
		if ( is_wp_error( $response ) ) {
1373
			if ( isset( $cache[ $cache_key ] ) && is_array( $cache[ $cache_key ] ) )
1374
				return $cache[ $cache_key ][ 'payload' ]; // return stale
1375
			else
1376
				return array();
1377
		}
1378
1379
		$results = json_decode( wp_remote_retrieve_body( $response ), true );
1380
		$related_posts = array();
1381
		if ( is_array( $results ) && !empty( $results['hits'] ) ) {
1382
			foreach( $results['hits'] as $hit ) {
1383
				$related_posts[] = array(
1384
					'id' => $hit['fields']['post_id'],
1385
				);
1386
			}
1387
		}
1388
1389
		// An empty array might indicate no related posts or that posts
1390
		// are not yet synced to WordPress.com, so we cache for only 1
1391
		// minute in this case
1392
		if ( empty( $related_posts ) ) {
1393
			$cache_ttl = 60;
1394
		} else {
1395
			$cache_ttl = 12 * HOUR_IN_SECONDS;
1396
		}
1397
1398
		// Update cache
1399
		if ( wp_using_ext_object_cache() ) {
1400
			set_transient( $transient_name, $related_posts, $cache_ttl );
0 ignored issues
show
Bug introduced by
The variable $transient_name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1401
		} else {
1402
			// Copy all valid cache values
1403
			$new_cache = array();
1404
			foreach ( $cache as $k => $v ) {
1405
				if ( is_array( $v ) && $v[ 'expires' ] > $now_ts ) {
1406
					$new_cache[ $k ] = $v;
1407
				}
1408
			}
1409
1410
			// Set new cache value
1411
			$cache_expires = $cache_ttl + $now_ts;
1412
			$new_cache[ $cache_key ] = array(
1413
				'expires' => $cache_expires,
1414
				'payload' => $related_posts,
1415
			);
1416
			update_post_meta( $post_id, $cache_meta_key, $new_cache );
1417
		}
1418
1419
		return $related_posts;
1420
	}
1421
1422
	/**
1423
	 * Filter out any hits that are not public anymore.
1424
	 *
1425
	 * @param array $related_posts
1426
	 * @uses get_post_stati, get_post_status
1427
	 * @return array
1428
	 */
1429
	protected function _filter_non_public_posts( array $related_posts ) {
1430
		$public_stati = get_post_stati( array( 'public' => true ) );
1431
1432
		$filtered = array();
1433
		foreach ( $related_posts as $hit ) {
1434
			if ( in_array( get_post_status( $hit['id'] ), $public_stati ) ) {
1435
				$filtered[] = $hit;
1436
			}
1437
		}
1438
		return $filtered;
1439
	}
1440
1441
	/**
1442
	 * Generates a context for the related content (second line in related post output).
1443
	 * Order of importance:
1444
	 *   - First category (Not 'Uncategorized')
1445
	 *   - First post tag
1446
	 *   - Number of comments
1447
	 *
1448
	 * @param int $post_id
1449
	 * @uses get_the_category, get_the_terms, get_comments_number, number_format_i18n, __, _n
1450
	 * @return string
1451
	 */
1452
	protected function _generate_related_post_context( $post_id ) {
1453
		$categories = get_the_category( $post_id );
1454 View Code Duplication
		if ( is_array( $categories ) ) {
1455
			foreach ( $categories as $category ) {
1456
				if ( 'uncategorized' != $category->slug && '' != trim( $category->name ) ) {
1457
					$post_cat_context = sprintf(
1458
						_x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
1459
						$category->name
1460
					);
1461
					/**
1462
					 * Filter the "In Category" line displayed in the post context below each Related Post.
1463
					 *
1464
					 * @module related-posts
1465
					 *
1466
					 * @since 3.2.0
1467
					 *
1468
					 * @param string $post_cat_context "In Category" line displayed in the post context below each Related Post.
1469
					 * @param array $category Array containing information about the category.
1470
					 */
1471
					return apply_filters( 'jetpack_relatedposts_post_category_context', $post_cat_context, $category );
1472
				}
1473
			}
1474
		}
1475
1476
		$tags = get_the_terms( $post_id, 'post_tag' );
1477 View Code Duplication
		if ( is_array( $tags ) ) {
1478
			foreach ( $tags as $tag ) {
1479
				if ( '' != trim( $tag->name ) ) {
1480
					$post_tag_context = sprintf(
1481
						_x( 'In "%s"', 'in {category/tag name}', 'jetpack' ),
1482
						$tag->name
1483
					);
1484
					/**
1485
					 * Filter the "In Tag" line displayed in the post context below each Related Post.
1486
					 *
1487
					 * @module related-posts
1488
					 *
1489
					 * @since 3.2.0
1490
					 *
1491
					 * @param string $post_tag_context "In Tag" line displayed in the post context below each Related Post.
1492
					 * @param array $tag Array containing information about the tag.
1493
					 */
1494
					return apply_filters( 'jetpack_relatedposts_post_tag_context', $post_tag_context, $tag );
1495
				}
1496
			}
1497
		}
1498
1499
		$comment_count = get_comments_number( $post_id );
1500
		if ( $comment_count > 0 ) {
1501
			return sprintf(
1502
				_n( 'With 1 comment', 'With %s comments', $comment_count, 'jetpack' ),
1503
				number_format_i18n( $comment_count )
1504
			);
1505
		}
1506
1507
		return __( 'Similar post', 'jetpack' );
1508
	}
1509
1510
	/**
1511
	 * Logs clicks for clickthrough analysis and related result tuning.
1512
	 *
1513
	 * @return null
1514
	 */
1515
	protected function _log_click( $post_id, $to_post_id, $link_position ) {
1516
1517
	}
1518
1519
	/**
1520
	 * Determines if the current post is able to use related posts.
1521
	 *
1522
	 * @uses self::get_options, is_admin, is_single, apply_filters
1523
	 * @return bool
1524
	 */
1525
	protected function _enabled_for_request() {
1526
		// Default to enabled
1527
		$enabled = true;
1528
1529
		// Must have feature enabled
1530
		$options = $this->get_options();
1531
		if ( ! $options['enabled'] ) {
1532
			$enabled = false;
1533
		}
1534
1535
		// Only run for frontend pages
1536
		if ( is_admin() ) {
1537
			$enabled = false;
1538
		}
1539
1540
		// Only run for standalone posts
1541
		if ( ! is_single() ) {
1542
			$enabled = false;
1543
		}
1544
1545
		/**
1546
		 * Filter the Enabled value to allow related posts to be shown on pages as well.
1547
		 *
1548
		 * @module related-posts
1549
		 *
1550
		 * @since 3.3.0
1551
		 *
1552
		 * @param bool $enabled Should Related Posts be enabled on the current page.
1553
		 */
1554
		return apply_filters( 'jetpack_relatedposts_filter_enabled_for_request', $enabled );
1555
	}
1556
1557
	/**
1558
	 * Adds filters and enqueues assets.
1559
	 *
1560
	 * @uses self::_enqueue_assets, self::_setup_shortcode, add_filter
1561
	 * @return null
1562
	 */
1563
	protected function _action_frontend_init_page() {
1564
		$this->_enqueue_assets( true, true );
1565
		$this->_setup_shortcode();
1566
1567
		add_filter( 'the_content', array( $this, 'filter_add_target_to_dom' ), 40 );
1568
	}
1569
1570
	/**
1571
	 * Enqueues assets needed to do async loading of related posts.
1572
	 *
1573
	 * @uses wp_enqueue_script, wp_enqueue_style, plugins_url
1574
	 * @return null
1575
	 */
1576
	protected function _enqueue_assets( $script, $style ) {
1577
		$dependencies = is_customize_preview() ? array( 'customize-base' ) : array( 'jquery' );
0 ignored issues
show
Unused Code introduced by
$dependencies is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1578
		if ( $script ) {
1579
			if ( $this->_citations_enabled )
1580
				wp_enqueue_script( 'jetpack_related-posts', plugins_url( 'auto-citations.js', __FILE__ ), array( 'jquery' ), self::VERSION );
1581
			else
1582
				wp_enqueue_script( 'jetpack_related-posts', plugins_url( 'related-posts.js', __FILE__ ), array( 'jquery' ), self::VERSION );
1583
1584
			$related_posts_js_options = array(
1585
				/**
1586
				 * Filter each Related Post Heading structure.
1587
				 *
1588
				 * @since 4.0.0
1589
				 *
1590
				 * @param string $str Related Post Heading structure. Default to h4.
1591
				 */
1592
				'post_heading' => apply_filters( 'jetpack_relatedposts_filter_post_heading', esc_attr( 'h4' ) ),
1593
			);
1594
			wp_localize_script( 'jetpack_related-posts', 'related_posts_js_options', $related_posts_js_options );
1595
		}
1596
		if ( $style ) {
1597
			if ( $this->_citations_enabled ) {
1598 View Code Duplication
				if ( is_rtl() ) {
1599
					wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'rtl/auto-citations-rtl.css', __FILE__ ), array(), self::VERSION );
1600
				} else {
1601
					wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'auto-citations.css', __FILE__ ), array(), self::VERSION );
1602
				}
1603 View Code Duplication
			} else {
1604
				if ( is_rtl() ) {
1605
					wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'rtl/related-posts-rtl.css', __FILE__ ), array(), self::VERSION );
1606
				} else {
1607
					wp_enqueue_style( 'jetpack_related-posts', plugins_url( 'related-posts.css', __FILE__ ), array(), self::VERSION );
1608
				}
1609
			}
1610
		}
1611
	}
1612
1613
	/**
1614
	 * Sets up the shortcode processing.
1615
	 *
1616
	 * @uses add_filter, add_shortcode
1617
	 * @return null
1618
	 */
1619
	protected function _setup_shortcode() {
1620
		add_filter( 'the_content', array( $this, 'test_for_shortcode' ), 0 );
1621
1622
		add_shortcode( self::SHORTCODE, array( $this, 'get_target_html' ) );
1623
	}
1624
1625
	protected function _allow_feature_toggle() {
1626
		if ( null === $this->_allow_feature_toggle ) {
1627
			/**
1628
			 * Filter the display of the Related Posts toggle in Settings > Reading.
1629
			 *
1630
			 * @module related-posts
1631
			 *
1632
			 * @since 2.8.0
1633
			 *
1634
			 * @param bool false Display a feature toggle. Default to false.
1635
			 */
1636
			$this->_allow_feature_toggle = apply_filters( 'jetpack_relatedposts_filter_allow_feature_toggle', false );
1637
		}
1638
		return $this->_allow_feature_toggle;
1639
	}
1640
1641
	/**
1642
	 * ===================================================
1643
	 * FUNCTIONS EXPOSING RELATED POSTS IN THE WP REST API
1644
	 * ===================================================
1645
	 */
1646
1647
	/**
1648
	 * Add Related Posts to the REST API Post response.
1649
	 *
1650
	 * @since 4.4.0
1651
	 *
1652
	 * @action rest_api_init
1653
	 * @uses register_rest_field, self::rest_get_related_posts
1654
	 * @return null
1655
	 */
1656
	public function rest_register_related_posts() {
1657
		register_rest_field( 'post',
1658
			'jetpack-related-posts',
1659
			array(
1660
				'get_callback' => array( $this, 'rest_get_related_posts' ),
1661
				'update_callback' => null,
1662
				'schema'          => null,
1663
			)
1664
		);
1665
	}
1666
1667
	/**
1668
	 * Build an array of Related Posts.
1669
	 *
1670
	 * @since 4.4.0
1671
	 *
1672
	 * @param array $object Details of current post.
1673
	 * @param string $field_name Name of field.
1674
	 * @param WP_REST_Request $request Current request
1675
	 *
1676
	 * @uses self::get_for_post_id
1677
	 *
1678
	 * @return array
1679
	 */
1680
	public function rest_get_related_posts( $object, $field_name, $request ) {
1681
		return $this->get_for_post_id( $object['id'], array() );
1682
	}
1683
}
1684
1685
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...
1686
	protected $_query_name;
1687
1688
	/**
1689
	 * Allows callers of this class to tag each query with a unique name for tracking purposes.
1690
	 *
1691
	 * @param string $name
1692
	 * @return Jetpack_RelatedPosts_Raw
1693
	 */
1694
	public function set_query_name( $name ) {
1695
		$this->_query_name = (string) $name;
1696
		return $this;
1697
	}
1698
1699
	/**
1700
	 * The raw related posts class can be used by other plugins or themes
1701
	 * to get related content. This class wraps the existing RelatedPosts
1702
	 * logic thus we never want to add anything to the DOM or do anything
1703
	 * for event hooks. We will also not present any settings for this
1704
	 * class and keep it enabled as calls to this class is done
1705
	 * programmatically.
1706
	 */
1707
	public function action_admin_init() {}
1708
	public function action_frontend_init() {}
1709
	public function get_options() {
1710
		return array(
1711
			'enabled' => true,
1712
		);
1713
	}
1714
1715
	/**
1716
	 * Workhorse method to return array of related posts ids matched by ElasticSearch.
1717
	 *
1718
	 * @param int $post_id
1719
	 * @param int $size
1720
	 * @param array $filters
1721
	 * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body
1722
	 * @return array
1723
	 */
1724
	protected function _get_related_posts( $post_id, $size, array $filters ) {
1725
		$hits = $this->_filter_non_public_posts(
1726
			$this->_get_related_post_ids(
1727
				$post_id,
1728
				$size,
1729
				$filters
1730
			)
1731
		);
1732
1733
		/** This filter is already documented in modules/related-posts/related-posts.php */
1734
		$hits = apply_filters( 'jetpack_relatedposts_filter_hits', $hits, $post_id );
1735
1736
		return $hits;
1737
	}
1738
1739
	/**
1740
	 * Workhorse method to return array of auto citation posts ids matched by ElasticSearch.
1741
	 *
1742
	 * @param int $post_id
1743
	 * @param int $size
1744
	 * @param array $filters
1745
	 * @uses wp_remote_post, is_wp_error, wp_remote_retrieve_body
1746
	 * @return array
1747
	 */
1748
	protected function _get_auto_citation_posts( $post_id, $size, array $filters ) {
1749
		return array();
1750
	}
1751
1752
}
1753