Passed
Push — master ( 6f0a6d...90a9ca )
by
unknown
09:41
created

MonsterInsights_SharedCount::get_more_counts()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 17
nc 6
nop 1
dl 0
loc 29
rs 9.0777
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * Handles the SharedCount integration and count grabbing.
5
 *
6
 * Class MonsterInsights_SharedCount
7
 */
8
class MonsterInsights_SharedCount {
9
10
	/**
11
	 * The action used to schedule daily events.
12
	 *
13
	 * @var string
14
	 */
15
	public $cron_key = 'monsterinsights_sharedcount_daily_update';
16
	/**
17
	 * Index progress key.
18
	 *
19
	 * @var string
20
	 */
21
	public static $progress_key = 'monsterinsights_sharedcount_index_progress';
22
	/**
23
	 * Index progress.
24
	 *
25
	 * @var array
26
	 */
27
	public static $progress;
28
	/**
29
	 * The error message from the api call.
30
	 *
31
	 * @var string
32
	 */
33
	public $error;
34
	/**
35
	 * The API endpoint.
36
	 *
37
	 * @var string
38
	 */
39
	private $endpoint = 'https://api.sharedcount.com/v1.0/';
40
	/**
41
	 * The API key to use for the requests.
42
	 *
43
	 * @var string
44
	 */
45
	private $api_key;
46
	/**
47
	 * If the current query needs to run again.
48
	 *
49
	 * @var bool
50
	 */
51
	private $more_pages = false;
52
53
	/**
54
	 * MonsterInsights_SharedCount constructor.
55
	 */
56
	public function __construct() {
57
58
		add_action( 'wp_ajax_monsterinsights_sharedcount_start_indexing', array( $this, 'ajax_start_indexing' ) );
59
		add_action( 'wp_ajax_monsterinsights_sharedcount_get_index_progress', array(
60
			$this,
61
			'ajax_get_index_progress'
62
		) );
63
64
		add_action( 'monsterinsights_sharedcount_get_more_posts', array( $this, 'get_more_counts' ) );
65
66
		add_action( 'monsterinsights_sharedcount_bulk_grab', array( $this, 'grab_and_store_bulk_by_id' ), 10, 2 );
67
68
		add_action( $this->cron_key, array( $this, 'daily_cron_update' ) );
69
	}
70
71
	/**
72
	 * AJAX handler from the Vue app that checks if the API key is set and handles
73
	 * an error message from the SharedCount API call. If the first call is successful it will schedule
74
	 * a daily cron to keep the counts fresh.
75
	 */
76
	public function ajax_start_indexing() {
77
78
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
79
80
		if ( $this->get_api_key() ) {
81
			if ( $this->start_posts_count() ) {
82
				$this->schedule_daily_update();
83
				wp_send_json_success( array(
84
					'max_pages' => $this->more_pages,
85
				) );
86
			} else {
87
				wp_send_json_error( array(
88
					'message' => $this->error,
89
				) );
90
			}
91
		}
92
93
		// No API key, let's send an error message.
94
		wp_send_json_error( array(
95
			'message' => esc_html__( 'The SharedCount API key is not set', 'google-analytics-for-wordpress' ),
96
		) );
97
98
	}
99
100
	/**
101
	 * Get the API key.
102
	 *
103
	 * @return string
104
	 */
105
	public function get_api_key() {
106
107
		if ( empty( $this->api_key ) ) {
108
			$this->api_key = monsterinsights_get_option( 'sharedcount_key' );
109
		}
110
111
		return $this->api_key;
112
	}
113
114
	/**
115
	 * Start a grabbing process that will schedule events to grab more pages if needed.
116
	 *
117
	 * @return bool
118
	 */
119
	public function start_posts_count() {
120
121
		return $this->get_more_counts( 1 );
122
123
	}
124
125
	/**
126
	 * Handler for the scheduled event to grab more data for sites with large number of posts.
127
	 * This is also used by the first call and uses the return value to determine if an error was encountered.
128
	 * The error gets set in the $error property and used for display.
129
	 *
130
	 * @param int $page The page number to grab counts for.
131
	 *
132
	 * @return bool
133
	 */
134
	public function get_more_counts( $page ) {
135
136
		$urls         = $this->get_post_urls( $page );
137
		$urls_as_keys = $this->urls_as_keys( $urls );
138
139
		if ( $this->use_bulk_api() ) {
140
			$bulk_request = $this->post_bulk_urls( $urls );
141
142
			if ( $bulk_request && ! empty( $bulk_request['bulk_id'] ) ) {
143
				$this->grab_and_store_bulk_by_id( $bulk_request['bulk_id'], $urls_as_keys );
144
			} else {
145
				return false;
146
			}
147
		} else {
148
			$store_counts = $this->grab_counts_one_by_one( $urls );
149
			if ( ! $store_counts ) {
150
				// Error encountered, return error.
151
				return false;
152
			}
153
		}
154
155
		$this->save_progress( $page, $this->more_pages );
0 ignored issues
show
Bug introduced by
It seems like $this->more_pages can also be of type false; however, parameter $max_pages of MonsterInsights_SharedCount::save_progress() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
		$this->save_progress( $page, /** @scrutinizer ignore-type */ $this->more_pages );
Loading history...
156
157
		if ( $this->more_pages ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->more_pages of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
158
			$page ++;
159
			$this->schedule_next_page( $page );
160
		}
161
162
		return true;
163
164
	}
165
166
	/**
167
	 * Save the current indexing progress.
168
	 *
169
	 * @param int $page The current page.
170
	 * @param int $max_pages The total number of pages.
171
	 */
172
	public function save_progress( $page, $max_pages ) {
173
		update_option( self::$progress_key, array(
174
			'page'      => $page,
175
			'max_pages' => $max_pages,
176
		), false );
177
	}
178
179
	/**
180
	 * Reset the progress option. Used for when the cron is disabled.
181
	 */
182
	public function reset_progress() {
183
		delete_option( self::$progress_key );
184
	}
185
186
	/**
187
	 * Use WP_Query to get a list of URLs to query SharedCount for share data.
188
	 *
189
	 * @param int $page The page number.
190
	 *
191
	 * @return array
192
	 */
193
	public function get_post_urls( $page = 1 ) {
194
195
		$posts_args  = array(
196
			'posts_per_page'   => 100, // Don't try to load more than 500 posts at once.
197
			'fields'           => 'ids', // Load just the ids.
198
			'paged'            => $page,
199
			'suppress_filters' => true, // Avoid loading additional functionality from other plugins/theme.
200
		);
201
		$posts_query = new WP_Query( $posts_args );
202
		$urls        = array();
203
204
		if ( $posts_query->have_posts() ) {
205
			while ( $posts_query->have_posts() ) {
206
				$posts_query->the_post();
207
208
				$urls[ get_the_ID() ] = get_permalink( get_the_ID() );
0 ignored issues
show
Bug introduced by
It seems like get_the_ID() can also be of type false; however, parameter $post of get_permalink() does only seem to accept WP_Post|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

208
				$urls[ get_the_ID() ] = get_permalink( /** @scrutinizer ignore-type */ get_the_ID() );
Loading history...
209
			}
210
		}
211
212
		if ( $posts_query->max_num_pages > $page ) {
213
			$this->more_pages = $posts_query->max_num_pages;
0 ignored issues
show
Documentation Bug introduced by
The property $more_pages was declared of type boolean, but $posts_query->max_num_pages is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
214
		} else {
215
			$this->more_pages = false;
216
		}
217
218
		wp_reset_postdata();
219
220
		return $urls;
221
	}
222
223
	/**
224
	 * Use URLs as array keys to make it easier to match with the post id.
225
	 *
226
	 * @param array $urls The urls with post ids as keys.
227
	 *
228
	 * @return array
229
	 */
230
	public function urls_as_keys( $urls ) {
231
232
		$urls_as_keys = array();
233
		foreach ( $urls as $id => $url ) {
234
			$urls_as_keys[ $url ] = $id;
235
		}
236
237
		return $urls_as_keys;
238
239
	}
240
241
	/**
242
	 * Helper method for using the bulk API. Disabled by default as the free api doesn't have access to it.
243
	 * This can be used by large sites to use less requests to the SharedCount API and grab data more efficiently
244
	 * if they have a paid license.
245
	 *
246
	 * @return mixed|void
247
	 */
248
	public function use_bulk_api() {
249
		// Bulk API is not available for free sharedcount accounts so let's set this to off by default.
250
		return apply_filters( 'monsterinsights_sharedcount_use_bulk_api', false );
251
	}
252
253
	/**
254
	 * Use the bulk API method to post data to the SharedCount API.
255
	 *
256
	 * @param array $urls An array with the URLs to be sent in the bulk request.
257
	 *
258
	 * @return bool|mixed
259
	 */
260
	public function post_bulk_urls( $urls ) {
261
262
		$body = implode( "\n", $urls );
263
264
		$request_url = add_query_arg(
265
			array(
266
				'apikey' => $this->get_api_key(),
267
			),
268
			$this->get_api_url( 'bulk' )
269
		);
270
271
		$request = wp_remote_post( $request_url, array(
272
			'body' => $body,
273
		) );
274
275
		$response        = wp_remote_retrieve_body( $request );
276
		$parsed_response = json_decode( $response, true );
277
		if ( 200 === wp_remote_retrieve_response_code( $request ) ) {
278
			return $parsed_response;
279
		} else {
280
			$this->handle_api_error( $parsed_response );
281
282
			return false;
283
		}
284
	}
285
286
	/**
287
	 * Get the API url.
288
	 *
289
	 * @param string $path The API path to use e.g. "bulk".
290
	 *
291
	 * @return string
292
	 */
293
	public function get_api_url( $path = '' ) {
294
		// Allow users to override the SharedCount URL if they have a custom URL.
295
		return apply_filters( 'monsterinsights_sharedcount_api_url', $this->endpoint . $path );
296
	}
297
298
	/**
299
	 * Generic handler for error responses from the SharedCount API.
300
	 * This uses the $error property to pass the error back for being displayed.
301
	 *
302
	 * @param array $parsed_response The response object from a SharedCount API call converted to an Array.
303
	 */
304
	public function handle_api_error( $parsed_response ) {
305
		if ( isset( $parsed_response['Error'] ) && isset( $parsed_response['Type'] ) && 'invalid_api_key' === $parsed_response['Type'] ) {
306
			$error = esc_html__( 'The SharedCount API key is invalid', 'google-analytics-for-wordpress' );
307
		} elseif ( ! empty( $parsed_response['quota_exceeded'] ) ) {
308
			$error = $parsed_response['quota_exceeded'];
309
		} else {
310
			$error = isset( $parsed_response['Error'] ) ? $parsed_response['Error'] : esc_html__( 'There was an error grabbing data from SharedCount, please check the API Key', 'google-analytics-for-wordpress' );
311
		}
312
		$this->error = $error;
313
	}
314
315
	/**
316
	 * Attempt to grab bulk data from the API by bulk id, if the bulk request is not completed
317
	 * schedule an event to try again in a minute.
318
	 *
319
	 * @param string $bulk_id The bulk id from the SharedCount bulk post request.
320
	 * @param array  $urls_as_keys An array of URLs where the keys are the URLs and the values are the post ids.
321
	 */
322
	public function grab_and_store_bulk_by_id( $bulk_id, $urls_as_keys ) {
323
		$bulk_data = $this->get_bulk_data( $bulk_id );
324
		// If the processing for the current bulk id is not completed schedule a single event to try again.
325
		if ( $bulk_data['_meta']['completed'] ) {
326
			$this->store_bulk_data( $bulk_data, $urls_as_keys );
0 ignored issues
show
Bug introduced by
It seems like $bulk_data can also be of type boolean; however, parameter $bulk_data of MonsterInsights_SharedCount::store_bulk_data() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

326
			$this->store_bulk_data( /** @scrutinizer ignore-type */ $bulk_data, $urls_as_keys );
Loading history...
327
		} else {
328
			$this->schedule_bulk_grabbing( $bulk_id, $urls_as_keys );
329
		}
330
	}
331
332
	/**
333
	 * Grab data from the SharedCount API using their Bulk API.
334
	 *
335
	 * @param string $bulk_id The bulk id from a POST request to the bulk API.
336
	 *
337
	 * @return bool|mixed
338
	 * @see MonsterInsights_SharedCount::post_bulk_urls()
339
	 *
340
	 */
341
	public function get_bulk_data( $bulk_id ) {
342
343
		$request_url = add_query_arg(
344
			array(
345
				'bulk_id' => $bulk_id,
346
				'apikey'  => $this->get_api_key(),
347
			),
348
			$this->get_api_url()
349
		);
350
351
		$request = wp_remote_get( $request_url );
352
353
		if ( 200 === wp_remote_retrieve_response_code( $request ) ) {
354
			$response        = wp_remote_retrieve_body( $request );
355
			$parsed_response = json_decode( $response, true );
356
357
			return $parsed_response;
358
		} else {
359
			return false;
360
		}
361
	}
362
363
	/**
364
	 * Iterate through the bulk data returned and store it in the post meta.
365
	 *
366
	 * @param array $bulk_data The bulk data response from the SharedCount API.
367
	 * @param array $urls_as_keys An array of URLs where the keys are the URLs and the values are the post ids.
368
	 */
369
	public function store_bulk_data( $bulk_data, $urls_as_keys ) {
370
		if ( ! empty( $bulk_data['data'] ) && is_array( $bulk_data['data'] ) ) {
371
			foreach ( $bulk_data['data'] as $url => $values ) {
372
				$post_id = array_key_exists( $url, $urls_as_keys ) ? $urls_as_keys[ $url ] : false;
373
374
				if ( $post_id ) {
375
					$this->store_post_counts( $post_id, $values );
376
				}
377
			}
378
		}
379
	}
380
381
	/**
382
	 * Save the post counts response to the post meta.
383
	 * The total value is saved separately for querying.
384
	 *
385
	 * @param int   $post_id The post id to save to.
386
	 * @param array $values The array of values received from the SharedCount API.
387
	 *
388
	 * @see MonsterInsights_SharedCount::get_counts_by_url()
389
	 */
390
	public function store_post_counts( $post_id, $values ) {
391
		$total_count = $this->combine_counts( $values );
392
		update_post_meta( $post_id, '_monsterinsights_sharedcount_total', $total_count );
393
		update_post_meta( $post_id, '_monsterinsights_sharedcount_values', $values );
394
	}
395
396
	/**
397
	 * Process a SharedCounts response and compile all counts into one number.
398
	 *
399
	 * @param array $response Array from decoding the API JSON response.
400
	 *
401
	 * @return int
402
	 */
403
	public function combine_counts( $response ) {
404
405
		$total = 0;
406
		if ( ! isset( $response['Error'] ) ) {
407
			foreach ( $response as $count ) {
408
				if ( is_int( $count ) ) {
409
					$total += $count;
410
				} elseif ( is_array( $count ) && isset( $count['share_count'] ) ) {
411
					$total += $count['share_count'];
412
				}
413
			}
414
		}
415
416
		return $total;
417
	}
418
419
	/**
420
	 * If the bulk request is not completed we need to schedule it to try again later.
421
	 *
422
	 * @param string $bulk_id The bulk id from the SharedCount bulk post request.
423
	 * @param array  $urls_as_keys An array of URLs where the keys are the URLs and the values are the post ids.
424
	 *
425
	 * @see MonsterInsights_SharedCount::post_bulk_urls()
426
	 * @see MonsterInsights_SharedCount::grab_and_store_bulk_by_id()
427
	 */
428
	public function schedule_bulk_grabbing( $bulk_id, $urls_as_keys ) {
429
430
		wp_schedule_single_event( time() + 60, 'monsterinsights_sharedcount_bulk_grab', array(
431
			'bulk_id' => $bulk_id,
432
			'urls'    => $urls_as_keys,
433
		) );
434
435
	}
436
437
	/**
438
	 * The SharedCount Bulk API is not available for free users so we need
439
	 * to use multiple calls to the API to grab data.
440
	 *
441
	 * @param array $urls An array of urls with the post ids as keys.
442
	 *
443
	 * @return bool
444
	 * @see MonsterInsights_SharedCount::get_post_urls()
445
	 *
446
	 */
447
	private function grab_counts_one_by_one( $urls ) {
448
449
		foreach ( $urls as $id => $url ) {
450
			$counts = $this->get_counts_by_url( $url );
451
452
			if ( $counts ) {
453
				$this->store_post_counts( $id, $counts );
0 ignored issues
show
Bug introduced by
It seems like $counts can also be of type true; however, parameter $values of MonsterInsights_SharedCount::store_post_counts() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

453
				$this->store_post_counts( $id, /** @scrutinizer ignore-type */ $counts );
Loading history...
454
			} else {
455
				// Return false to display error message from API request.
456
				return false;
457
			}
458
		}
459
460
		return true;
461
462
	}
463
464
	/**
465
	 * Request the SharedCount data from the API by URL.
466
	 *
467
	 * @param string $url The URL to request data for.
468
	 *
469
	 * @return bool|mixed
470
	 */
471
	public function get_counts_by_url( $url ) {
472
473
		$url         = apply_filters( 'monsterinsights_sharedcount_url_pre_grab', $url );
474
		$request_url = add_query_arg(
475
			array(
476
				'url'    => $url,
477
				'apikey' => $this->get_api_key(),
478
			),
479
			$this->get_api_url()
480
		);
481
482
		$request         = wp_remote_get( $request_url );
483
		$response        = wp_remote_retrieve_body( $request );
484
		$parsed_response = json_decode( $response, true );
485
		if ( 200 === wp_remote_retrieve_response_code( $request ) ) {
486
			return $parsed_response;
487
		} else {
488
			$this->handle_api_error( $parsed_response );
489
490
			return false;
491
		}
492
493
	}
494
495
	/**
496
	 * Schedule a single event for the next page in the WP Query to be grabbed.
497
	 *
498
	 * @param int $page The page number.
499
	 */
500
	public function schedule_next_page( $page ) {
501
502
		wp_schedule_single_event( time() + 60, 'monsterinsights_sharedcount_get_more_posts', array( 'page' => $page ) );
503
504
	}
505
506
	/**
507
	 * This schedules the daily event with the first one in 24hrs from the current time.
508
	 */
509
	public function schedule_daily_update() {
510
511
		if ( ! wp_next_scheduled( $this->cron_key ) ) {
512
			wp_schedule_event( time() + DAY_IN_SECONDS, 'daily', $this->cron_key );
513
		}
514
515
	}
516
517
	/**
518
	 * Cron handler that checks if the sorting method is still set to SharedCount.
519
	 * If the sorting method changed, it will disable the daily cron.
520
	 */
521
	public function daily_cron_update() {
522
		$sort_option = monsterinsights_get_option( 'popular_posts_inline_sort', 'comments' );
523
524
		if ( 'sharedcount' === $sort_option ) {
525
			$this->start_posts_count();
526
		} else {
527
			$this->disable_counts_updates();
528
		}
529
	}
530
531
	/**
532
	 * Disable cron and reset progress.
533
	 */
534
	public function disable_counts_updates() {
535
		// If we are no longer using this option disable the cron.
536
		wp_clear_scheduled_hook( $this->cron_key );
537
		$this->reset_progress();
538
	}
539
540
	/**
541
	 * Get the post counts based on a post id.
542
	 * Not used currently.
543
	 *
544
	 * @param int $post_id The id of the post.
545
	 *
546
	 * @return bool|mixed
547
	 */
548
	public function get_post_counts( $post_id ) {
549
		$post_url = get_permalink( $post_id );
550
551
		return $this->combine_counts( $this->get_counts_by_url( $post_url ) );
0 ignored issues
show
Bug introduced by
It seems like $post_url can also be of type false; however, parameter $url of MonsterInsights_SharedCount::get_counts_by_url() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

551
		return $this->combine_counts( $this->get_counts_by_url( /** @scrutinizer ignore-type */ $post_url ) );
Loading history...
Bug introduced by
It seems like $this->get_counts_by_url($post_url) can also be of type boolean; however, parameter $response of MonsterInsights_SharedCount::combine_counts() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

551
		return $this->combine_counts( /** @scrutinizer ignore-type */ $this->get_counts_by_url( $post_url ) );
Loading history...
552
	}
553
554
	/**
555
	 * Get the indexing progress as percent.
556
	 *
557
	 * @return int
558
	 */
559
	public static function get_index_progress_percent() {
560
561
		$progress = self::get_index_progress();
562
563
		if ( ! empty( $progress ) && ! empty( $progress['page'] ) && ! empty( $progress['max_pages'] ) ) {
564
			$progress = 100 / $progress['max_pages'] * $progress['page'];
565
			$progress = floor( $progress );
566
567
			return $progress;
568
		} elseif ( isset( $progress['max_pages'] ) && false === $progress['max_pages'] ) {
569
			return 100;
570
		}
571
572
		return 0;
573
574
	}
575
576
	/**
577
	 * Get the current progress.
578
	 *
579
	 * @return array
580
	 */
581
	public static function get_index_progress() {
582
583
		if ( empty( self::$progress ) ) {
584
			self::$progress = get_option( self::$progress_key, array() );
0 ignored issues
show
Documentation Bug introduced by
It seems like get_option(self::progress_key, array()) can also be of type false. However, the property $progress is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
585
		}
586
587
		return self::$progress;
588
589
	}
590
591
	/**
592
	 * Get the index progress with ajax.
593
	 */
594
	public function ajax_get_index_progress() {
595
		wp_send_json( array(
596
			'progress' => self::get_index_progress_percent(),
597
		) );
598
	}
599
600
	/**
601
	 * Get the top popular posts by SharedCount shares.
602
	 *
603
	 * @param int $count The number of posts to get.
604
	 *
605
	 * @return array
606
	 */
607
	public static function query_popular_posts( $count = 5 ) {
608
609
		$popular_posts_args  = array(
610
			'posts_per_page' => $count,
611
			'meta_value'     => 'monsterinsights_sharedcount_total',
612
			'orderby'        => 'meta_value_num',
613
			'order'          => 'DESC',
614
		);
615
		$popular_posts_query = new WP_Query( $popular_posts_args );
616
		$popular_posts       = array();
617
618
		if ( $popular_posts_query->have_posts() ) {
619
			while ( $popular_posts_query->have_posts() ) {
620
				$popular_posts_query->the_post();
621
				$popular_posts[ get_the_ID() ] = array(
622
					'post_title' => get_the_title(),
623
					'permalink'  => get_permalink(),
624
					'thumbnail'  => get_the_post_thumbnail_url( get_the_ID(), 'medium' ),
0 ignored issues
show
Bug introduced by
It seems like get_the_ID() can also be of type false; however, parameter $post of get_the_post_thumbnail_url() does only seem to accept WP_Post|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

624
					'thumbnail'  => get_the_post_thumbnail_url( /** @scrutinizer ignore-type */ get_the_ID(), 'medium' ),
Loading history...
625
				);
626
			}
627
		}
628
629
		wp_reset_postdata();
630
631
		return $popular_posts;
632
633
	}
634
635
}
636
637
new MonsterInsights_SharedCount();
638