MonsterInsights_SharedCount::save_progress()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 3
b 0
f 0
nc 1
nop 2
dl 0
loc 5
rs 10
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
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
78
79
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
80
			return;
81
		}
82
83
		if ( $this->get_api_key() ) {
84
			if ( $this->start_posts_count() ) {
85
				$this->schedule_daily_update();
86
				wp_send_json_success( array(
87
					'max_pages' => $this->more_pages,
88
				) );
89
			} else {
90
				wp_send_json_error( array(
91
					'message' => $this->error,
92
				) );
93
			}
94
		}
95
96
		// No API key, let's send an error message.
97
		wp_send_json_error( array(
98
			'message' => esc_html__( 'The SharedCount API key is not set', 'google-analytics-for-wordpress' ),
99
		) );
100
101
	}
102
103
	/**
104
	 * Get the API key.
105
	 *
106
	 * @return string
107
	 */
108
	public function get_api_key() {
109
110
		if ( empty( $this->api_key ) ) {
111
			$this->api_key = monsterinsights_get_option( 'sharedcount_key' );
112
		}
113
114
		return $this->api_key;
115
	}
116
117
	/**
118
	 * Start a grabbing process that will schedule events to grab more pages if needed.
119
	 *
120
	 * @return bool
121
	 */
122
	public function start_posts_count() {
123
124
		return $this->get_more_counts( 1 );
125
126
	}
127
128
	/**
129
	 * Handler for the scheduled event to grab more data for sites with large number of posts.
130
	 * This is also used by the first call and uses the return value to determine if an error was encountered.
131
	 * The error gets set in the $error property and used for display.
132
	 *
133
	 * @param int $page The page number to grab counts for.
134
	 *
135
	 * @return bool
136
	 */
137
	public function get_more_counts( $page ) {
138
139
		$urls         = $this->get_post_urls( $page );
140
		$urls_as_keys = $this->urls_as_keys( $urls );
141
142
		if ( $this->use_bulk_api() ) {
143
			$bulk_request = $this->post_bulk_urls( $urls );
144
145
			if ( $bulk_request && ! empty( $bulk_request['bulk_id'] ) ) {
146
				$this->grab_and_store_bulk_by_id( $bulk_request['bulk_id'], $urls_as_keys );
147
			} else {
148
				return false;
149
			}
150
		} else {
151
			$store_counts = $this->grab_counts_one_by_one( $urls );
152
			if ( ! $store_counts ) {
153
				// Error encountered, return error.
154
				return false;
155
			}
156
		}
157
158
		$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

158
		$this->save_progress( $page, /** @scrutinizer ignore-type */ $this->more_pages );
Loading history...
159
160
		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...
161
			$page ++;
162
			$this->schedule_next_page( $page );
163
		}
164
165
		return true;
166
167
	}
168
169
	/**
170
	 * Save the current indexing progress.
171
	 *
172
	 * @param int $page The current page.
173
	 * @param int $max_pages The total number of pages.
174
	 */
175
	public function save_progress( $page, $max_pages ) {
176
		update_option( self::$progress_key, array(
177
			'page'      => $page,
178
			'max_pages' => $max_pages,
179
		), false );
180
	}
181
182
	/**
183
	 * Reset the progress option. Used for when the cron is disabled.
184
	 */
185
	public function reset_progress() {
186
		delete_option( self::$progress_key );
187
	}
188
189
	/**
190
	 * Use WP_Query to get a list of URLs to query SharedCount for share data.
191
	 *
192
	 * @param int $page The page number.
193
	 *
194
	 * @return array
195
	 */
196
	public function get_post_urls( $page = 1 ) {
197
198
		$posts_args  = array(
199
			'posts_per_page'   => 100, // Don't try to load more than 500 posts at once.
200
			'fields'           => 'ids', // Load just the ids.
201
			'paged'            => $page,
202
			'suppress_filters' => true, // Avoid loading additional functionality from other plugins/theme.
203
		);
204
		$posts_query = new WP_Query( $posts_args );
205
		$urls        = array();
206
207
		if ( $posts_query->have_posts() ) {
208
			while ( $posts_query->have_posts() ) {
209
				$posts_query->the_post();
210
211
				$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

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

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

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

554
		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

554
		return $this->combine_counts( /** @scrutinizer ignore-type */ $this->get_counts_by_url( $post_url ) );
Loading history...
555
	}
556
557
	/**
558
	 * Get the indexing progress as percent.
559
	 *
560
	 * @return int
561
	 */
562
	public static function get_index_progress_percent() {
563
564
		$progress = self::get_index_progress();
565
566
		if ( ! empty( $progress ) && ! empty( $progress['page'] ) && ! empty( $progress['max_pages'] ) ) {
567
			$progress = 100 / $progress['max_pages'] * $progress['page'];
568
			$progress = floor( $progress );
569
570
			return $progress;
571
		} elseif ( isset( $progress['max_pages'] ) && false === $progress['max_pages'] ) {
572
			return 100;
573
		}
574
575
		return 0;
576
577
	}
578
579
	/**
580
	 * Get the current progress.
581
	 *
582
	 * @return array
583
	 */
584
	public static function get_index_progress() {
585
586
		if ( empty( self::$progress ) ) {
587
			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...
588
		}
589
590
		return self::$progress;
591
592
	}
593
594
	/**
595
	 * Get the index progress with ajax.
596
	 */
597
	public function ajax_get_index_progress() {
598
		check_ajax_referer( 'mi-admin-nonce', 'nonce' );
599
600
		if ( ! current_user_can( 'monsterinsights_save_settings' ) ) {
601
			return;
602
		}
603
604
		wp_send_json( array(
605
			'progress' => self::get_index_progress_percent(),
606
		) );
607
	}
608
609
	/**
610
	 * Get the top popular posts by SharedCount shares.
611
	 *
612
	 * @param int $count The number of posts to get.
613
	 *
614
	 * @return array
615
	 */
616
	public static function query_popular_posts( $count = 5 ) {
617
618
		$popular_posts_args  = array(
619
			'posts_per_page' => $count,
620
			'meta_value'     => 'monsterinsights_sharedcount_total',
621
			'orderby'        => 'meta_value_num',
622
			'order'          => 'DESC',
623
		);
624
		$popular_posts_query = new WP_Query( $popular_posts_args );
625
		$popular_posts       = array();
626
627
		if ( $popular_posts_query->have_posts() ) {
628
			while ( $popular_posts_query->have_posts() ) {
629
				$popular_posts_query->the_post();
630
				$popular_posts[ get_the_ID() ] = array(
631
					'post_title' => get_the_title(),
632
					'permalink'  => get_permalink(),
633
					'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

633
					'thumbnail'  => get_the_post_thumbnail_url( /** @scrutinizer ignore-type */ get_the_ID(), 'medium' ),
Loading history...
634
				);
635
			}
636
		}
637
638
		wp_reset_postdata();
639
640
		return $popular_posts;
641
642
	}
643
644
}
645
646
new MonsterInsights_SharedCount();
647