PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.3.2
Jetpack – WP Security, Backup, Speed, & Growth v12.3.2
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / widgets / top-posts.php
jetpack / modules / widgets Last commit date
authors 8 years ago contact-info 5 years ago eu-cookie-law 4 years ago facebook-likebox 11 years ago flickr 4 years ago gallery 4 years ago goodreads 5 years ago google-translate 4 years ago image-widget 8 years ago instagram 6 years ago migrate-to-core 3 years ago milestone 3 years ago my-community 8 years ago simple-payments 4 years ago social-icons 4 years ago social-media-icons 5 years ago top-posts 8 years ago wordpress-post-widget 3 years ago authors.php 3 years ago blog-stats.php 3 years ago class-jetpack-eu-cookie-law-widget.php 3 years ago class-jetpack-instagram-widget.php 3 years ago contact-info.php 3 years ago customizer-controls.css 9 years ago customizer-utils.js 6 years ago facebook-likebox.php 3 years ago flickr.php 3 years ago gallery.php 3 years ago goodreads.php 3 years ago google-translate.php 3 years ago gravatar-profile.css 10 years ago gravatar-profile.php 3 years ago image-widget.php 3 years ago internet-defense-league.php 3 years ago mailchimp.php 3 years ago milestone.php 5 years ago my-community.php 3 years ago rsslinks-widget.php 3 years ago simple-payments.php 3 years ago social-icons.php 3 years ago social-media-icons.php 3 years ago top-posts.php 3 years ago twitter-timeline-admin.js 6 years ago twitter-timeline.php 3 years ago upcoming-events.php 3 years ago wordpress-post-widget.php 4 years ago
top-posts.php
850 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Top Posts widget.
4 *
5 * Currently, this widget depends on the Stats Module. To not load this file
6 * when the Stats Module is not active would potentially bypass Jetpack's
7 * fatal error detection on module activation, so we always load this file.
8 * Instead, we don't register the widget if the Stats Module isn't active.
9 *
10 * @package automattic/jetpack
11 */
12
13 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
14
15 use Automattic\Jetpack\Image_CDN\Image_CDN_Core;
16 use Automattic\Jetpack\Redirect;
17 use Automattic\Jetpack\Stats\WPCOM_Stats;
18 use Automattic\Jetpack\Status;
19
20 /**
21 * Register the widget for use in Appearance -> Widgets
22 */
23 add_action( 'widgets_init', 'jetpack_top_posts_widget_init' );
24
25 /**
26 * Register the widget, if the Stats module is active.
27 */
28 function jetpack_top_posts_widget_init() {
29 // Currently, this widget depends on the Stats Module.
30 if (
31 ! ( defined( 'IS_WPCOM' ) && IS_WPCOM )
32 && (
33 ! Jetpack::is_module_active( 'stats' )
34 || ( new Status() )->is_offline_mode()
35 )
36 ) {
37 return;
38 }
39
40 register_widget( 'Jetpack_Top_Posts_Widget' );
41 }
42
43 /**
44 * Widget class.
45 */
46 class Jetpack_Top_Posts_Widget extends WP_Widget {
47 /**
48 * Widget unique identifier.
49 *
50 * @var string
51 */
52 public $alt_option_name = 'widget_stats_topposts';
53
54 /**
55 * Widget default title.
56 *
57 * @var string
58 */
59 public $default_title = '';
60
61 /**
62 * Constructor.
63 */
64 public function __construct() {
65 parent::__construct(
66 'top-posts',
67 /** This filter is documented in modules/widgets/facebook-likebox.php */
68 apply_filters( 'jetpack_widget_name', __( 'Top Posts &amp; Pages', 'jetpack' ) ),
69 array(
70 'description' => __( 'Shows your most viewed posts and pages.', 'jetpack' ),
71 'customize_selective_refresh' => true,
72 )
73 );
74
75 $this->default_title = __( 'Top Posts &amp; Pages', 'jetpack' );
76
77 if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
78 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
79 }
80
81 /**
82 * Add explanation about how the statistics are calculated.
83 *
84 * @module widgets
85 *
86 * @since 3.9.3
87 */
88 add_action( 'jetpack_widget_top_posts_after_fields', array( $this, 'stats_explanation' ) );
89 }
90
91 /**
92 * Enqueue stylesheet.
93 */
94 public function enqueue_style() {
95 wp_register_style( 'jetpack-top-posts-widget', plugins_url( 'top-posts/style.css', __FILE__ ), array(), '20141013' );
96 wp_enqueue_style( 'jetpack-top-posts-widget' );
97 }
98
99 /**
100 * Displays the form for this widget on the Widgets page of the WP Admin area.
101 *
102 * @param array $instance Instance configuration.
103 *
104 * @return void
105 */
106 public function form( $instance ) {
107 $instance = wp_parse_args( (array) $instance, static::defaults() );
108
109 if ( false === $instance['title'] ) {
110 $instance['title'] = $this->default_title;
111 }
112 $title = stripslashes( $instance['title'] );
113
114 $count = isset( $instance['count'] ) ? (int) $instance['count'] : 10;
115 if ( $count < 1 || 10 < $count ) {
116 $count = 10;
117 }
118
119 $allowed_post_types = array_values( get_post_types( array( 'public' => true ) ) );
120 $types = isset( $instance['types'] ) ? (array) $instance['types'] : array( 'post', 'page' );
121
122 // 'likes' are not available in Jetpack
123 $ordering = isset( $instance['ordering'] ) && 'likes' === $instance['ordering'] ? 'likes' : 'views';
124
125 if ( isset( $instance['display'] ) && in_array( $instance['display'], array( 'grid', 'list', 'text' ), true ) ) {
126 $display = $instance['display'];
127 } else {
128 $display = 'text';
129 }
130
131 ?>
132
133 <p>
134 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
135 <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
136 </p>
137
138 <p>
139 <label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_html_e( 'Maximum number of posts to show (no more than 10):', 'jetpack' ); ?></label>
140 <input id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>" type="number" value="<?php echo (int) $count; ?>" min="1" max="10" />
141 </p>
142
143 <?php if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) : ?>
144 <p>
145 <label><?php esc_html_e( 'Order Top Posts &amp; Pages By:', 'jetpack' ); ?></label>
146 <ul>
147 <li><label><input id="<?php echo esc_attr( $this->get_field_id( 'ordering' ) ); ?>-likes" name="<?php echo esc_attr( $this->get_field_name( 'ordering' ) ); ?>" type="radio" value="likes" <?php checked( 'likes', $ordering ); ?> /> <?php esc_html_e( 'Likes', 'jetpack' ); ?></label></li>
148 <li><label><input id="<?php echo esc_attr( $this->get_field_id( 'ordering' ) ); ?>-views" name="<?php echo esc_attr( $this->get_field_name( 'ordering' ) ); ?>" type="radio" value="views" <?php checked( 'views', $ordering ); ?> /> <?php esc_html_e( 'Views', 'jetpack' ); ?></label></li>
149 </ul>
150 </p>
151 <?php endif; ?>
152
153 <p>
154 <label for="<?php echo esc_attr( $this->get_field_id( 'types' ) ); ?>"><?php esc_html_e( 'Types of pages to display:', 'jetpack' ); ?></label>
155 <ul>
156 <?php
157 foreach ( $allowed_post_types as $type ) {
158 // Get the Post Type name to display next to the checkbox.
159 $post_type_object = get_post_type_object( $type );
160 $label = $post_type_object->labels->name;
161
162 $checked = '';
163 if ( in_array( $type, $types, true ) ) {
164 $checked = 'checked="checked" ';
165 }
166 ?>
167
168 <li><label>
169 <input
170 value="<?php echo esc_attr( $type ); ?>"
171 name="<?php echo esc_attr( $this->get_field_name( 'types' ) ); ?>[]"
172 id="<?php echo esc_attr( $this->get_field_id( 'types' ) . '-' . $type ); ?>"
173 type="checkbox"
174 <?php echo $checked; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
175 >
176 <?php echo esc_html( $label ); ?>
177 </label></li>
178
179 <?php } // End foreach ?>
180 </ul>
181 </p>
182
183 <p>
184 <label><?php esc_html_e( 'Display as:', 'jetpack' ); ?></label>
185 <ul>
186 <li><label><input id="<?php echo esc_attr( $this->get_field_id( 'display' ) ); ?>-text" name="<?php echo esc_attr( $this->get_field_name( 'display' ) ); ?>" type="radio" value="text" <?php checked( 'text', $display ); ?> /> <?php esc_html_e( 'Text List', 'jetpack' ); ?></label></li>
187 <li><label><input id="<?php echo esc_attr( $this->get_field_id( 'display' ) ); ?>-list" name="<?php echo esc_attr( $this->get_field_name( 'display' ) ); ?>" type="radio" value="list" <?php checked( 'list', $display ); ?> /> <?php esc_html_e( 'Image List', 'jetpack' ); ?></label></li>
188 <li><label><input id="<?php echo esc_attr( $this->get_field_id( 'display' ) ); ?>-grid" name="<?php echo esc_attr( $this->get_field_name( 'display' ) ); ?>" type="radio" value="grid" <?php checked( 'grid', $display ); ?> /> <?php esc_html_e( 'Image Grid', 'jetpack' ); ?></label></li>
189 </ul>
190 </p>
191 <?php
192
193 /**
194 * Fires after the fields are displayed in the Top Posts Widget settings in wp-admin.
195 *
196 * Allow adding extra content after the fields are displayed.
197 *
198 * @module widgets
199 *
200 * @since 3.9.3
201 *
202 * @param array $args {
203 * @param array $instance The widget instance.
204 * @param object $this The class object.
205 * }
206 */
207 do_action( 'jetpack_widget_top_posts_after_fields', array( $instance, $this ) );
208 }
209
210 /**
211 * Explains how the statics are calculated.
212 */
213 public function stats_explanation() {
214 echo '<p>';
215 esc_html_e( 'Top Posts &amp; Pages by views are calculated from 24-48 hours of stats. They take a while to change.', 'jetpack' );
216 echo '</p>';
217 }
218
219 /**
220 * Deals with the settings when they are saved by the admin.
221 *
222 * @param array $new_instance New configuration values.
223 * @param array $old_instance Old configuration values.
224 *
225 * @return array
226 */
227 public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
228 $instance = array();
229 $instance['title'] = wp_kses( $new_instance['title'], array() );
230 if ( $instance['title'] === $this->default_title ) {
231 $instance['title'] = false; // Store as false in case of language change.
232 }
233
234 $instance['count'] = (int) $new_instance['count'];
235 if ( $instance['count'] < 1 || 10 < $instance['count'] ) {
236 $instance['count'] = 10;
237 }
238
239 // 'likes' are not available in Jetpack
240 $instance['ordering'] = isset( $new_instance['ordering'] ) && 'likes' === $new_instance['ordering']
241 ? 'likes'
242 : 'views';
243
244 $allowed_post_types = array_values( get_post_types( array( 'public' => true ) ) );
245 $instance['types'] = $new_instance['types'];
246 foreach ( $new_instance['types'] as $key => $type ) {
247 if ( ! in_array( $type, $allowed_post_types, true ) ) {
248 unset( $new_instance['types'][ $key ] );
249 }
250 }
251
252 if ( isset( $new_instance['display'] ) && in_array( $new_instance['display'], array( 'grid', 'list', 'text' ), true ) ) {
253 $instance['display'] = $new_instance['display'];
254 } else {
255 $instance['display'] = 'text';
256 }
257
258 /**
259 * Filters Top Posts Widget settings before they're saved.
260 *
261 * @module widgets
262 *
263 * @since 3.9.3
264 *
265 * @param array $instance The santized widget instance. Only contains data processed by the current widget.
266 * @param array $new_instance The new widget instance before sanitization.
267 */
268 $instance = apply_filters( 'jetpack_top_posts_saving', $instance, $new_instance );
269
270 return $instance;
271 }
272
273 /**
274 * Outputs the HTML for this widget.
275 *
276 * @param array $args An array of standard parameters for widgets in this theme.
277 * @param array $instance An array of settings for this widget instance.
278 *
279 * @return void Echoes it's output
280 */
281 public function widget( $args, $instance ) {
282 /** This action is documented in modules/widgets/gravatar-profile.php */
283 do_action( 'jetpack_stats_extra', 'widget_view', 'top_posts' );
284
285 $instance = wp_parse_args( (array) $instance, static::defaults() );
286
287 $title = isset( $instance['title'] ) ? $instance['title'] : false;
288 if ( false === $title ) {
289 $title = $this->default_title;
290 }
291
292 /** This filter is documented in core/src/wp-includes/default-widgets.php */
293 $title = apply_filters( 'widget_title', $title );
294
295 $count = isset( $instance['count'] ) ? (int) $instance['count'] : false;
296 if ( $count < 1 || 10 < $count ) {
297 $count = 10;
298 }
299 /**
300 * Control the number of displayed posts.
301 *
302 * @module widgets
303 *
304 * @since 3.3.0
305 *
306 * @param string $count Number of Posts displayed in the Top Posts widget. Default is 10.
307 */
308 $count = apply_filters( 'jetpack_top_posts_widget_count', $count );
309
310 $types = isset( $instance['types'] ) ? (array) $instance['types'] : array( 'post', 'page' );
311
312 // 'likes' are not available in Jetpack
313 $ordering = isset( $instance['ordering'] ) && 'likes' === $instance['ordering']
314 ? 'likes'
315 : 'views';
316
317 if (
318 isset( $instance['display'] )
319 && in_array( $instance['display'], array( 'grid', 'list', 'text' ), true )
320 ) {
321 $display = $instance['display'];
322 } else {
323 $display = 'text';
324 }
325
326 $get_image_options = array();
327 if ( 'text' !== $display ) {
328 $get_image_options = array(
329 'fallback_to_avatars' => true,
330 /** This filter is documented in modules/stats.php */
331 'gravatar_default' => apply_filters( 'jetpack_static_url', set_url_scheme( 'https://en.wordpress.com/i/logo/white-gray-80.png' ) ),
332 'avatar_size' => 40,
333 'width' => null,
334 'height' => null,
335 );
336 if ( 'grid' === $display ) {
337 $get_image_options['avatar_size'] = 200;
338 }
339 /**
340 * Top Posts Widget Image options.
341 *
342 * @module widgets
343 *
344 * @since 1.8.0
345 *
346 * @param array $get_image_options {
347 * Array of Image options.
348 * @type bool true Should we default to Gravatars when no image is found? Default is true.
349 * @type string $gravatar_default Default Image URL if no Gravatar is found.
350 * @type int $avatar_size Default Image size.
351 * @type mixed $width Image width, not set by default and $avatar_size is used instead.
352 * @type mixed $height Image height, not set by default and $avatar_size is used instead.
353 * }
354 */
355 $get_image_options = apply_filters( 'jetpack_top_posts_widget_image_options', $get_image_options );
356 }
357
358 if ( function_exists( 'wpl_get_blogs_most_liked_posts' ) && 'likes' === $ordering ) {
359 $posts = $this->get_by_likes( $count, $types );
360 } else {
361 $posts = $this->get_by_views( $count, $args, $types );
362 }
363
364 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
365
366 if ( ! empty( $title ) ) {
367 echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
368 }
369
370 /*
371 * If we have no posts, add some fallback posts
372 * and display a fallback message for admins.
373 */
374 if ( ! $posts ) {
375 if ( current_user_can( 'edit_theme_options' ) ) {
376 echo self::fallback_message(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
377 }
378
379 $posts = $this->get_fallback_posts( $count, $types );
380 }
381
382 /*
383 * Display our posts.
384 */
385
386 /**
387 * Filter the layout of the Top Posts Widget
388 *
389 * @module widgets
390 *
391 * @since 6.4.0
392 *
393 * @param string $layout layout of the Top Posts Widget (empty string).
394 * @param array $posts IDs of the posts to be displayed.
395 * @param array $display Display option from widget form.
396 */
397 $layout = apply_filters( 'jetpack_top_posts_widget_layout', '', $posts, $display );
398 if ( ! empty( $layout ) ) {
399 echo $layout; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
400 }
401
402 switch ( $display ) {
403 case 'list':
404 case 'grid':
405 // Keep the avatar_size as default dimensions for backward compatibility.
406 $width = (int) $get_image_options['avatar_size'];
407 $height = (int) $get_image_options['avatar_size'];
408
409 // Check if the user has changed the width.
410 if ( ! empty( $get_image_options['width'] ) ) {
411 $width = (int) $get_image_options['width'];
412 }
413
414 // Check if the user has changed the height.
415 if ( ! empty( $get_image_options['height'] ) ) {
416 $height = (int) $get_image_options['height'];
417 }
418
419 foreach ( $posts as &$post ) {
420 $image = Jetpack_PostImages::get_image(
421 $post['post_id'],
422 array(
423 'fallback_to_avatars' => (bool) $get_image_options['fallback_to_avatars'],
424 'width' => (int) $width,
425 'height' => (int) $height,
426 'avatar_size' => (int) $get_image_options['avatar_size'],
427 )
428 );
429
430 if ( $image ) {
431
432 $post['image'] = $image['src'];
433 if ( 'blavatar' !== $image['from'] && 'gravatar' !== $image['from'] ) {
434 $post['image'] = Image_CDN_Core::cdn_url( $post['image'], array( 'resize' => "$width,$height" ) );
435 }
436 }
437 }
438 unset( $post );
439
440 if ( 'grid' === $display ) {
441 echo "<div class='widgets-grid-layout no-grav'>\n";
442 foreach ( $posts as $post ) {
443 echo '<div class="widget-grid-view-image">';
444
445 /**
446 * Fires before each Top Post result, inside <li>.
447 *
448 * @module widgets
449 *
450 * @since 3.2.0
451 *
452 * @param string $post['post_id'] Post ID.
453 */
454 do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] );
455
456 /**
457 * Filter the permalink of items in the Top Posts widget.
458 *
459 * @module widgets
460 *
461 * @since 4.4.0
462 *
463 * @param string $post['permalink'] Post permalink.
464 * @param array $post Post array.
465 */
466 $filtered_permalink = apply_filters( 'jetpack_top_posts_widget_permalink', $post['permalink'], $post );
467
468 if ( $post['image'] ) {
469 printf(
470 '<a href="%1$s" title="%2$s" class="bump-view" data-bump-view="tp"%3$s><img width="%4$d" height="%5$d" src="%6$s" alt="%2$s" data-pin-nopin="true"/></a>',
471 esc_url( $filtered_permalink ),
472 esc_attr( wp_kses( $post['title'], array() ) ),
473 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
474 absint( $width ),
475 absint( $height ),
476 esc_url( $post['image'] )
477 );
478 }
479
480 /**
481 * Fires after each Top Post result, inside <li>.
482 *
483 * @module widgets
484 *
485 * @since 3.2.0
486 *
487 * @param string $post['post_id'] Post ID.
488 */
489 do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] );
490
491 echo '</div>';
492 }
493 echo "</div>\n";
494 } else {
495 echo "<ul class='widgets-list-layout no-grav'>\n";
496 foreach ( $posts as $post ) {
497 echo '<li>';
498
499 /** This action is documented in modules/widgets/top-posts.php */
500 do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] );
501
502 /** This filter is documented in modules/widgets/top-posts.php */
503 $filtered_permalink = apply_filters( 'jetpack_top_posts_widget_permalink', $post['permalink'], $post );
504
505 if ( $post['image'] ) {
506 printf(
507 '<a href="%1$s" title="%2$s" class="bump-view" data-bump-view="tp"%3$s><img width="%4$d" height="%5$d" src="%6$s" alt="%2$s" data-pin-nopin="true" class="widgets-list-layout-blavatar" /></a>',
508 esc_url( $filtered_permalink ),
509 esc_attr( wp_kses( $post['title'], array() ) ),
510 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
511 absint( $width ),
512 absint( $height ),
513 esc_url( $post['image'] )
514 );
515 }
516
517 printf(
518 '<div class="widgets-list-layout-links">
519 <a href="%1$s" title="%2$s" class="bump-view" data-bump-view="tp"%3$s>%4$s</a>
520 </div>
521 ',
522 esc_url( $filtered_permalink ),
523 esc_attr( wp_kses( $post['title'], array() ) ),
524 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
525 esc_html( wp_kses( $post['title'], array() ) )
526 );
527
528 /** This action is documented in modules/widgets/top-posts.php */
529 do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] );
530
531 echo '</li>';
532 }
533 echo "</ul>\n";
534 }
535 break;
536 default:
537 echo '<ul>';
538
539 foreach ( $posts as $post ) {
540 echo '<li>';
541
542 /** This action is documented in modules/widgets/top-posts.php */
543 do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] );
544
545 /** This filter is documented in modules/widgets/top-posts.php */
546 $filtered_permalink = apply_filters( 'jetpack_top_posts_widget_permalink', $post['permalink'], $post );
547
548 printf(
549 '<a href="%1$s" class="bump-view" data-bump-view="tp"%2$s>%3$s</a>',
550 esc_url( $filtered_permalink ),
551 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
552 esc_html( wp_kses( $post['title'], array() ) )
553 );
554
555 /** This action is documented in modules/widgets/top-posts.php */
556 do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] );
557
558 echo '</li>';
559 }
560
561 echo '</ul>';
562 break;
563 }
564
565 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
566 }
567
568 /**
569 * Display a message with recommendations when there are no recorded top posts.
570 *
571 * @return string $fallback_message
572 */
573 private static function fallback_message() {
574 $link = esc_url( Redirect::get_url( 'jetpack-support-getting-more-views-and-traffic' ) );
575 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
576 $link = 'https://en.support.wordpress.com/getting-more-site-traffic/';
577 }
578
579 $fallback_message = '<p>';
580 $fallback_message .= sprintf(
581 wp_kses(
582 /* Translators: Placeholder: link to the Jetpack support article. */
583 __( 'There are no popular posts to display. Instead, your visitors will see a list of your recent posts below. <a href="%s" target="_blank">Want more traffic?</a>', 'jetpack' ),
584 array(
585 'a' => array(
586 'href' => array(),
587 'target' => array(),
588 ),
589 )
590 ),
591 esc_url( $link )
592 );
593 $fallback_message .= '<p>';
594
595 return $fallback_message;
596 }
597
598 /**
599 * Widget default option values.
600 */
601 public static function defaults() {
602 return array(
603 'title' => esc_html__( 'Top Posts &amp; Pages', 'jetpack' ),
604 'count' => absint( 10 ),
605 'types' => array( 'post', 'page' ),
606 'ordering' => 'views',
607 'display' => 'text',
608 );
609 }
610
611 /**
612 * Get most liked posts
613 *
614 * ONLY TO BE USED IN WPCOM
615 *
616 * @since 8.4.0 Added $types param
617 *
618 * @param int $count The maximum number of posts to be returned.
619 * @param array $types The post types that should be returned. Optional. Defaults to 'post' and 'page'.
620 *
621 * @return array array of posts.
622 */
623 public function get_by_likes( $count, $types = array( 'post', 'page' ) ) {
624 $post_likes = wpl_get_blogs_most_liked_posts();
625 if ( ! $post_likes ) {
626 return array();
627 }
628
629 return $this->get_posts( array_keys( $post_likes ), $count, $types );
630 }
631
632 /**
633 * Get the top posts based on views
634 *
635 * @since 8.4.0 Added $types param
636 *
637 * @param int $count The maximum number of posts to be returned.
638 * @param array $args The widget arguments.
639 * @param array $types The post types that should be returned.
640 *
641 * @return array array of posts. Defaults to 'post' and 'page'.
642 */
643 public function get_by_views( $count, $args, $types = array( 'post', 'page' ) ) {
644 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
645 $post_views = wp_cache_get( "get_top_posts_$count", 'stats' );
646 if ( false === $post_views ) {
647 $stats_get_daily_history = stats_get_daily_history(
648 false,
649 get_current_blog_id(),
650 'postviews',
651 'post_id',
652 false,
653 2,
654 '',
655 $count * 2 + 10,
656 true
657 );
658 $post_views = array_shift( $stats_get_daily_history );
659 unset( $post_views[0] );
660 wp_cache_add( "get_top_posts_$count", $post_views, 'stats', 1200 );
661 }
662
663 return $this->get_posts( array_keys( $post_views ), $count, $types );
664 }
665
666 /**
667 * Filter the number of days used to calculate Top Posts for the Top Posts widget.
668 * We do not recommend accessing more than 10 days of results at one.
669 * When more than 10 days of results are accessed at once, results should be cached via the WordPress transients API.
670 * Querying for -1 days will give results for an infinite number of days.
671 *
672 * @module widgets
673 *
674 * @since 3.9.3
675 *
676 * @param int 2 Number of days. Default is 2.
677 * @param array $args The widget arguments.
678 */
679 $days = (int) apply_filters( 'jetpack_top_posts_days', 2, $args );
680
681 /** Handling situations where the number of days makes no sense - allows for unlimited days where $days = -1 */
682 if ( 0 === $days || false === $days ) {
683 $days = 2;
684 }
685
686 $query_args = array(
687 'max' => 11,
688 'summarize' => 1,
689 'num' => (int) $days,
690 );
691 $post_view_posts = convert_stats_array_to_object( ( new WPCOM_Stats() )->get_top_posts( $query_args ) );
692
693 if ( ! isset( $post_view_posts->summary ) || empty( $post_view_posts->summary->postviews ) ) {
694 return array();
695 }
696
697 $post_view_ids = array_filter( wp_list_pluck( $post_view_posts->summary->postviews, 'id' ) );
698
699 if ( ! $post_view_ids ) {
700 return array();
701 }
702
703 return $this->get_posts( $post_view_ids, $count, $types );
704 }
705
706 /**
707 * Get some posts if no posts are found in the stats API
708 *
709 * @since 8.4.0 Added $count and $types
710 *
711 * @param int $count The maximum number of posts to be returned.
712 * @param array $types The post types that should be returned.
713 * @return array
714 */
715 public function get_fallback_posts( $count = 10, $types = array( 'post', 'page' ) ) {
716 $post_query = new WP_Query();
717
718 if ( ! is_array( $types ) || empty( $types ) ) {
719 $types = array( 'post', 'page' );
720 }
721
722 $posts = $post_query->query(
723 array(
724 'posts_per_page' => $count,
725 'post_status' => 'publish',
726 'post_type' => $types,
727 'no_found_rows' => true,
728 'fields' => 'ids',
729 )
730 );
731
732 if ( ! $posts ) {
733 return array();
734 }
735
736 return $this->get_posts( $posts, $count, $types );
737 }
738
739 /**
740 * Get posts from an array of IDs
741 *
742 * @since 8.4.0 Added $types parameters
743 *
744 * @param array $post_ids The post IDs.
745 * @param int $count The maximum number of posts to return.
746 * @param array $types The post types that should be returned. Optional. Defaults to 'post', 'page'.
747 * @return array
748 */
749 public function get_posts( $post_ids, $count, $types = array( 'post', 'page' ) ) {
750 $counter = 0;
751
752 if ( ! is_array( $types ) || empty( $types ) ) {
753 $types = array( 'post', 'page' );
754 }
755
756 $posts = array();
757 foreach ( (array) $post_ids as $post_id ) {
758 $post = get_post( $post_id );
759
760 if ( ! $post ) {
761 continue;
762 }
763
764 /**
765 * Attachment pages use the 'inherit' post status by default.
766 * To be able to remove attachment pages from private and password protect posts,
767 * we need to replace their post status by the parent post' status.
768 */
769 if ( 'inherit' === $post->post_status && 'attachment' === $post->post_type ) {
770 $post->post_status = get_post_status( $post_id );
771 }
772
773 // hide private and password protected posts.
774 if ( 'publish' !== $post->post_status || ! empty( $post->post_password ) ) {
775 continue;
776 }
777
778 // Filter by chosen Post Types.
779 if ( ! in_array( $post->post_type, $types, true ) ) {
780 continue;
781 }
782
783 // Both get HTML stripped etc on display.
784 if ( empty( $post->post_title ) ) {
785 $title_source = $post->post_content;
786 $title = wp_html_excerpt( $title_source, 50 );
787 $title .= '&hellip;';
788 } else {
789 $title = $post->post_title;
790 }
791
792 $permalink = get_permalink( $post->ID );
793
794 $post_type = $post->post_type;
795
796 $posts[] = compact( 'title', 'permalink', 'post_id', 'post_type' );
797 ++$counter;
798
799 if ( $counter == $count ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
800 break; // only need to load and show x number of likes.
801 }
802 }
803
804 /**
805 * Filter the Top Posts and Pages.
806 *
807 * @module widgets
808 *
809 * @since 3.0.0
810 *
811 * @param array $posts Array of the most popular posts.
812 * @param array $post_ids Array of Post IDs.
813 * @param string $count Number of Top Posts we want to display.
814 */
815 return apply_filters( 'jetpack_widget_get_top_posts', $posts, $post_ids, $count );
816 }
817 }
818
819 /**
820 * Create a shortcode to display the widget anywhere.
821 *
822 * @since 3.9.2
823 *
824 * @param array $instance Saved values from database.
825 */
826 function jetpack_do_top_posts_widget( $instance ) {
827 // Post Types can't be entered as an array in the shortcode parameters.
828 if ( isset( $instance['types'] ) && is_string( $instance['types'] ) ) {
829 $instance['types'] = explode( ',', $instance['types'] );
830 }
831
832 $instance = shortcode_atts(
833 Jetpack_Top_Posts_Widget::defaults(),
834 $instance,
835 'jetpack_top_posts_widget'
836 );
837
838 // Add a class to allow styling.
839 $args = array(
840 'before_widget' => sprintf( '<div class="%s">', 'jetpack_top_posts_widget' ),
841 );
842
843 ob_start();
844 the_widget( 'Jetpack_Top_Posts_Widget', $instance, $args );
845 $output = ob_get_clean();
846
847 return $output;
848 }
849 add_shortcode( 'jetpack_top_posts_widget', 'jetpack_do_top_posts_widget' );
850