PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.7.3
Jetpack – WP Security, Backup, Speed, & Growth v12.7.3
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 2 years ago facebook-likebox 11 years ago flickr 2 years ago gallery 4 years ago goodreads 5 years ago google-translate 4 years ago image-widget 8 years ago instagram 6 years ago internet-defense-league 3 years ago migrate-to-core 3 years ago milestone 2 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 2 years ago class-jetpack-eu-cookie-law-widget.php 3 years ago class-jetpack-instagram-widget.php 2 years ago contact-info.php 2 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 2 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 2 years ago rsslinks-widget.php 3 years ago simple-payments.php 2 years ago social-icons.php 2 years ago social-media-icons.php 3 years ago top-posts.php 2 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
859 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\Redirect;
16 use Automattic\Jetpack\Stats\WPCOM_Stats;
17 use Automattic\Jetpack\Status;
18
19 // Register the widget for use in Appearance -> Widgets
20 add_action( 'widgets_init', 'jetpack_top_posts_widget_init' );
21
22 /**
23 * Register the widget, if the Stats module is active.
24 */
25 function jetpack_top_posts_widget_init() {
26 // Currently, this widget depends on the Stats Module.
27 if (
28 ! ( defined( 'IS_WPCOM' ) && IS_WPCOM )
29 && (
30 ! Jetpack::is_module_active( 'stats' )
31 || ( new Status() )->is_offline_mode()
32 )
33 ) {
34 return;
35 }
36
37 register_widget( 'Jetpack_Top_Posts_Widget' );
38 }
39
40 /**
41 * Widget class.
42 */
43 class Jetpack_Top_Posts_Widget extends WP_Widget {
44 /**
45 * Widget unique identifier.
46 *
47 * @var string
48 */
49 public $alt_option_name = 'widget_stats_topposts';
50
51 /**
52 * Widget default title.
53 *
54 * @var string
55 */
56 public $default_title = '';
57
58 /**
59 * Constructor.
60 */
61 public function __construct() {
62 parent::__construct(
63 'top-posts',
64 /** This filter is documented in modules/widgets/facebook-likebox.php */
65 apply_filters( 'jetpack_widget_name', __( 'Top Posts &amp; Pages', 'jetpack' ) ),
66 array(
67 'description' => __( 'Shows your most viewed posts and pages.', 'jetpack' ),
68 'customize_selective_refresh' => true,
69 )
70 );
71
72 $this->default_title = __( 'Top Posts &amp; Pages', 'jetpack' );
73
74 if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
75 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
76 }
77
78 /**
79 * Add explanation about how the statistics are calculated.
80 *
81 * @module widgets
82 *
83 * @since 3.9.3
84 */
85 add_action( 'jetpack_widget_top_posts_after_fields', array( $this, 'stats_explanation' ) );
86 }
87
88 /**
89 * Enqueue stylesheet.
90 */
91 public function enqueue_style() {
92 wp_register_style( 'jetpack-top-posts-widget', plugins_url( 'top-posts/style.css', __FILE__ ), array(), '20141013' );
93 wp_enqueue_style( 'jetpack-top-posts-widget' );
94 }
95
96 /**
97 * Displays the form for this widget on the Widgets page of the WP Admin area.
98 *
99 * @param array $instance Instance configuration.
100 *
101 * @return void
102 */
103 public function form( $instance ) {
104 $instance = wp_parse_args( (array) $instance, static::defaults() );
105
106 if ( false === $instance['title'] ) {
107 $instance['title'] = $this->default_title;
108 }
109 $title = stripslashes( $instance['title'] );
110
111 $count = isset( $instance['count'] ) ? (int) $instance['count'] : 10;
112 if ( $count < 1 || 10 < $count ) {
113 $count = 10;
114 }
115
116 $allowed_post_types = array_values( get_post_types( array( 'public' => true ) ) );
117 $types = isset( $instance['types'] ) ? (array) $instance['types'] : array( 'post', 'page' );
118
119 // 'likes' are not available in Jetpack
120 $ordering = isset( $instance['ordering'] ) && 'likes' === $instance['ordering'] ? 'likes' : 'views';
121
122 if ( isset( $instance['display'] ) && in_array( $instance['display'], array( 'grid', 'list', 'text' ), true ) ) {
123 $display = $instance['display'];
124 } else {
125 $display = 'text';
126 }
127
128 ?>
129
130 <p>
131 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
132 <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 ); ?>" />
133 </p>
134
135 <p>
136 <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>
137 <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" />
138 </p>
139
140 <?php if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) : ?>
141 <p>
142 <label><?php esc_html_e( 'Order Top Posts &amp; Pages By:', 'jetpack' ); ?></label>
143 <ul>
144 <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>
145 <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>
146 </ul>
147 </p>
148 <?php endif; ?>
149
150 <p>
151 <label for="<?php echo esc_attr( $this->get_field_id( 'types' ) ); ?>"><?php esc_html_e( 'Types of pages to display:', 'jetpack' ); ?></label>
152 <ul>
153 <?php
154 foreach ( $allowed_post_types as $type ) {
155 // Get the Post Type name to display next to the checkbox.
156 $post_type_object = get_post_type_object( $type );
157 $label = $post_type_object->labels->name;
158
159 $checked = '';
160 if ( in_array( $type, $types, true ) ) {
161 $checked = 'checked="checked" ';
162 }
163 ?>
164
165 <li><label>
166 <input
167 value="<?php echo esc_attr( $type ); ?>"
168 name="<?php echo esc_attr( $this->get_field_name( 'types' ) ); ?>[]"
169 id="<?php echo esc_attr( $this->get_field_id( 'types' ) . '-' . $type ); ?>"
170 type="checkbox"
171 <?php echo $checked; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
172 >
173 <?php echo esc_html( $label ); ?>
174 </label></li>
175
176 <?php } // End foreach ?>
177 </ul>
178 </p>
179
180 <p>
181 <label><?php esc_html_e( 'Display as:', 'jetpack' ); ?></label>
182 <ul>
183 <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>
184 <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>
185 <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>
186 </ul>
187 </p>
188 <?php
189
190 /**
191 * Fires after the fields are displayed in the Top Posts Widget settings in wp-admin.
192 *
193 * Allow adding extra content after the fields are displayed.
194 *
195 * @module widgets
196 *
197 * @since 3.9.3
198 *
199 * @param array $args {
200 * @param array $instance The widget instance.
201 * @param object $this The class object.
202 * }
203 */
204 do_action( 'jetpack_widget_top_posts_after_fields', array( $instance, $this ) );
205 }
206
207 /**
208 * Explains how the statics are calculated.
209 */
210 public function stats_explanation() {
211 echo '<p>';
212 esc_html_e( 'Top Posts &amp; Pages by views are calculated from 24-48 hours of stats. They take a while to change.', 'jetpack' );
213 echo '</p>';
214 }
215
216 /**
217 * Deals with the settings when they are saved by the admin.
218 *
219 * @param array $new_instance New configuration values.
220 * @param array $old_instance Old configuration values.
221 *
222 * @return array
223 */
224 public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
225 $instance = array();
226 $instance['title'] = wp_kses( $new_instance['title'], array() );
227 if ( $instance['title'] === $this->default_title ) {
228 $instance['title'] = false; // Store as false in case of language change.
229 }
230
231 $instance['count'] = (int) $new_instance['count'];
232 if ( $instance['count'] < 1 || 10 < $instance['count'] ) {
233 $instance['count'] = 10;
234 }
235
236 // 'likes' are not available in Jetpack
237 $instance['ordering'] = isset( $new_instance['ordering'] ) && 'likes' === $new_instance['ordering']
238 ? 'likes'
239 : 'views';
240
241 $allowed_post_types = array_values( get_post_types( array( 'public' => true ) ) );
242 $instance['types'] = $new_instance['types'];
243 foreach ( $new_instance['types'] as $key => $type ) {
244 if ( ! in_array( $type, $allowed_post_types, true ) ) {
245 unset( $new_instance['types'][ $key ] );
246 }
247 }
248
249 if ( isset( $new_instance['display'] ) && in_array( $new_instance['display'], array( 'grid', 'list', 'text' ), true ) ) {
250 $instance['display'] = $new_instance['display'];
251 } else {
252 $instance['display'] = 'text';
253 }
254
255 /**
256 * Filters Top Posts Widget settings before they're saved.
257 *
258 * @module widgets
259 *
260 * @since 3.9.3
261 *
262 * @param array $instance The santized widget instance. Only contains data processed by the current widget.
263 * @param array $new_instance The new widget instance before sanitization.
264 */
265 $instance = apply_filters( 'jetpack_top_posts_saving', $instance, $new_instance );
266
267 return $instance;
268 }
269
270 /**
271 * Outputs the HTML for this widget.
272 *
273 * @param array $args An array of standard parameters for widgets in this theme.
274 * @param array $instance An array of settings for this widget instance.
275 *
276 * @return void Echoes it's output
277 */
278 public function widget( $args, $instance ) {
279 /** This action is documented in modules/widgets/gravatar-profile.php */
280 do_action( 'jetpack_stats_extra', 'widget_view', 'top_posts' );
281
282 $instance = wp_parse_args( (array) $instance, static::defaults() );
283
284 $title = isset( $instance['title'] ) ? $instance['title'] : false;
285 if ( false === $title ) {
286 $title = $this->default_title;
287 }
288
289 /** This filter is documented in core/src/wp-includes/default-widgets.php */
290 $title = apply_filters( 'widget_title', $title );
291
292 $count = isset( $instance['count'] ) ? (int) $instance['count'] : false;
293 if ( $count < 1 || 10 < $count ) {
294 $count = 10;
295 }
296 /**
297 * Control the number of displayed posts.
298 *
299 * @module widgets
300 *
301 * @since 3.3.0
302 *
303 * @param string $count Number of Posts displayed in the Top Posts widget. Default is 10.
304 */
305 $count = apply_filters( 'jetpack_top_posts_widget_count', $count );
306
307 $types = isset( $instance['types'] ) ? (array) $instance['types'] : array( 'post', 'page' );
308
309 // 'likes' are not available in Jetpack
310 $ordering = isset( $instance['ordering'] ) && 'likes' === $instance['ordering']
311 ? 'likes'
312 : 'views';
313
314 if (
315 isset( $instance['display'] )
316 && in_array( $instance['display'], array( 'grid', 'list', 'text' ), true )
317 ) {
318 $display = $instance['display'];
319 } else {
320 $display = 'text';
321 }
322
323 $get_image_options = array();
324 if ( 'text' !== $display ) {
325 $get_image_options = array(
326 'fallback_to_avatars' => true,
327 /** This filter is documented in modules/stats.php */
328 'gravatar_default' => apply_filters( 'jetpack_static_url', set_url_scheme( 'https://en.wordpress.com/i/logo/white-gray-80.png' ) ),
329 'avatar_size' => 40,
330 'width' => null,
331 'height' => null,
332 );
333 if ( 'grid' === $display ) {
334 $get_image_options['avatar_size'] = 200;
335 }
336 /**
337 * Top Posts Widget Image options.
338 *
339 * @module widgets
340 *
341 * @since 1.8.0
342 *
343 * @param array $get_image_options {
344 * Array of Image options.
345 * @type bool true Should we default to Gravatars when no image is found? Default is true.
346 * @type string $gravatar_default Default Image URL if no Gravatar is found.
347 * @type int $avatar_size Default Image size.
348 * @type mixed $width Image width, not set by default and $avatar_size is used instead.
349 * @type mixed $height Image height, not set by default and $avatar_size is used instead.
350 * }
351 */
352 $get_image_options = apply_filters( 'jetpack_top_posts_widget_image_options', $get_image_options );
353 }
354
355 if ( function_exists( 'wpl_get_blogs_most_liked_posts' ) && 'likes' === $ordering ) {
356 $posts = $this->get_by_likes( $count, $types );
357 } else {
358 $posts = $this->get_by_views( $count, $args, $types );
359 }
360
361 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
362
363 if ( ! empty( $title ) ) {
364 echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
365 }
366
367 /*
368 * If we have no posts, add some fallback posts
369 * and display a fallback message for admins.
370 */
371 if ( ! $posts ) {
372 if ( current_user_can( 'edit_theme_options' ) ) {
373 echo self::fallback_message(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
374 }
375
376 $posts = $this->get_fallback_posts( $count, $types );
377 }
378
379 /*
380 * Display our posts.
381 */
382
383 /**
384 * Filter the layout of the Top Posts Widget
385 *
386 * @module widgets
387 *
388 * @since 6.4.0
389 *
390 * @param string $layout layout of the Top Posts Widget (empty string).
391 * @param array $posts IDs of the posts to be displayed.
392 * @param array $display Display option from widget form.
393 */
394 $layout = apply_filters( 'jetpack_top_posts_widget_layout', '', $posts, $display );
395 if ( ! empty( $layout ) ) {
396 echo $layout; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
397 }
398
399 switch ( $display ) {
400 case 'list':
401 case 'grid':
402 // Keep the avatar_size as default dimensions for backward compatibility.
403 $width = (int) $get_image_options['avatar_size'];
404 $height = (int) $get_image_options['avatar_size'];
405
406 // Check if the user has changed the width.
407 if ( ! empty( $get_image_options['width'] ) ) {
408 $width = (int) $get_image_options['width'];
409 }
410
411 // Check if the user has changed the height.
412 if ( ! empty( $get_image_options['height'] ) ) {
413 $height = (int) $get_image_options['height'];
414 }
415
416 foreach ( $posts as &$post ) {
417 $image = Jetpack_PostImages::get_image(
418 $post['post_id'],
419 array(
420 'fallback_to_avatars' => (bool) $get_image_options['fallback_to_avatars'],
421 'width' => (int) $width,
422 'height' => (int) $height,
423 'avatar_size' => (int) $get_image_options['avatar_size'],
424 )
425 );
426
427 if ( $image ) {
428 $post['image'] = Jetpack_PostImages::fit_image_url(
429 $image['src'],
430 $width,
431 $height
432 );
433
434 $post['image_srcset'] = Jetpack_PostImages::generate_cropped_srcset(
435 $image,
436 $width,
437 $height
438 );
439
440 if ( empty( $post['image_srcset'] ) ) {
441 $post['image_srcset'] = "{$post['image']} 1x";
442 }
443 }
444 }
445 unset( $post );
446
447 if ( 'grid' === $display ) {
448 echo "<div class='widgets-grid-layout no-grav'>\n";
449 foreach ( $posts as $post ) {
450 echo '<div class="widget-grid-view-image">';
451
452 /**
453 * Fires before each Top Post result, inside <li>.
454 *
455 * @module widgets
456 *
457 * @since 3.2.0
458 *
459 * @param string $post['post_id'] Post ID.
460 */
461 do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] );
462
463 /**
464 * Filter the permalink of items in the Top Posts widget.
465 *
466 * @module widgets
467 *
468 * @since 4.4.0
469 *
470 * @param string $post['permalink'] Post permalink.
471 * @param array $post Post array.
472 */
473 $filtered_permalink = apply_filters( 'jetpack_top_posts_widget_permalink', $post['permalink'], $post );
474
475 if ( $post['image'] ) {
476 printf(
477 '<a href="%1$s" title="%2$s" class="bump-view" data-bump-view="tp"%3$s><img loading="lazy" width="%4$d" height="%5$d" src="%6$s" srcset="%7$s" alt="%2$s" data-pin-nopin="true"/></a>',
478 esc_url( $filtered_permalink ),
479 esc_attr( wp_kses( $post['title'], array() ) ),
480 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
481 absint( $width ),
482 absint( $height ),
483 esc_url( $post['image'] ),
484 esc_attr( $post['image_srcset'] )
485 );
486 }
487
488 /**
489 * Fires after each Top Post result, inside <li>.
490 *
491 * @module widgets
492 *
493 * @since 3.2.0
494 *
495 * @param string $post['post_id'] Post ID.
496 */
497 do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] );
498
499 echo '</div>';
500 }
501 echo "</div>\n";
502 } else {
503 echo "<ul class='widgets-list-layout no-grav'>\n";
504 foreach ( $posts as $post ) {
505 echo '<li>';
506
507 /** This action is documented in modules/widgets/top-posts.php */
508 do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] );
509
510 /** This filter is documented in modules/widgets/top-posts.php */
511 $filtered_permalink = apply_filters( 'jetpack_top_posts_widget_permalink', $post['permalink'], $post );
512
513 if ( $post['image'] ) {
514 printf(
515 '<a href="%1$s" title="%2$s" class="bump-view" data-bump-view="tp"%3$s><img loading="lazy" width="%4$d" height="%5$d" src="%6$s" srcset="%7$s" alt="%2$s" data-pin-nopin="true" class="widgets-list-layout-blavatar" /></a>',
516 esc_url( $filtered_permalink ),
517 esc_attr( wp_kses( $post['title'], array() ) ),
518 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
519 absint( $width ),
520 absint( $height ),
521 esc_url( $post['image'] ),
522 esc_attr( $post['image_srcset'] )
523 );
524 }
525
526 printf(
527 '<div class="widgets-list-layout-links">
528 <a href="%1$s" title="%2$s" class="bump-view" data-bump-view="tp"%3$s>%4$s</a>
529 </div>
530 ',
531 esc_url( $filtered_permalink ),
532 esc_attr( wp_kses( $post['title'], array() ) ),
533 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
534 esc_html( wp_kses( $post['title'], array() ) )
535 );
536
537 /** This action is documented in modules/widgets/top-posts.php */
538 do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] );
539
540 echo '</li>';
541 }
542 echo "</ul>\n";
543 }
544 break;
545 default:
546 echo '<ul>';
547
548 foreach ( $posts as $post ) {
549 echo '<li>';
550
551 /** This action is documented in modules/widgets/top-posts.php */
552 do_action( 'jetpack_widget_top_posts_before_post', $post['post_id'] );
553
554 /** This filter is documented in modules/widgets/top-posts.php */
555 $filtered_permalink = apply_filters( 'jetpack_top_posts_widget_permalink', $post['permalink'], $post );
556
557 printf(
558 '<a href="%1$s" class="bump-view" data-bump-view="tp"%2$s>%3$s</a>',
559 esc_url( $filtered_permalink ),
560 ( get_queried_object_id() === $post['post_id'] ? ' aria-current="page"' : '' ),
561 esc_html( wp_kses( $post['title'], array() ) )
562 );
563
564 /** This action is documented in modules/widgets/top-posts.php */
565 do_action( 'jetpack_widget_top_posts_after_post', $post['post_id'] );
566
567 echo '</li>';
568 }
569
570 echo '</ul>';
571 break;
572 }
573
574 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
575 }
576
577 /**
578 * Display a message with recommendations when there are no recorded top posts.
579 *
580 * @return string $fallback_message
581 */
582 private static function fallback_message() {
583 $link = esc_url( Redirect::get_url( 'jetpack-support-getting-more-views-and-traffic' ) );
584 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
585 $link = 'https://en.support.wordpress.com/getting-more-site-traffic/';
586 }
587
588 $fallback_message = '<p>';
589 $fallback_message .= sprintf(
590 wp_kses(
591 /* Translators: Placeholder: link to the Jetpack support article. */
592 __( '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' ),
593 array(
594 'a' => array(
595 'href' => array(),
596 'target' => array(),
597 ),
598 )
599 ),
600 esc_url( $link )
601 );
602 $fallback_message .= '<p>';
603
604 return $fallback_message;
605 }
606
607 /**
608 * Widget default option values.
609 */
610 public static function defaults() {
611 return array(
612 'title' => esc_html__( 'Top Posts &amp; Pages', 'jetpack' ),
613 'count' => absint( 10 ),
614 'types' => array( 'post', 'page' ),
615 'ordering' => 'views',
616 'display' => 'text',
617 );
618 }
619
620 /**
621 * Get most liked posts
622 *
623 * ONLY TO BE USED IN WPCOM
624 *
625 * @since 8.4.0 Added $types param
626 *
627 * @param int $count The maximum number of posts to be returned.
628 * @param array $types The post types that should be returned. Optional. Defaults to 'post' and 'page'.
629 *
630 * @return array array of posts.
631 */
632 public function get_by_likes( $count, $types = array( 'post', 'page' ) ) {
633 $post_likes = wpl_get_blogs_most_liked_posts();
634 if ( ! $post_likes ) {
635 return array();
636 }
637
638 return $this->get_posts( array_keys( $post_likes ), $count, $types );
639 }
640
641 /**
642 * Get the top posts based on views
643 *
644 * @since 8.4.0 Added $types param
645 *
646 * @param int $count The maximum number of posts to be returned.
647 * @param array $args The widget arguments.
648 * @param array $types The post types that should be returned.
649 *
650 * @return array array of posts. Defaults to 'post' and 'page'.
651 */
652 public function get_by_views( $count, $args, $types = array( 'post', 'page' ) ) {
653 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
654 $post_views = wp_cache_get( "get_top_posts_$count", 'stats' );
655 if ( false === $post_views ) {
656 $stats_get_daily_history = stats_get_daily_history(
657 false,
658 get_current_blog_id(),
659 'postviews',
660 'post_id',
661 false,
662 2,
663 '',
664 $count * 2 + 10,
665 true
666 );
667 $post_views = array_shift( $stats_get_daily_history );
668 unset( $post_views[0] );
669 wp_cache_add( "get_top_posts_$count", $post_views, 'stats', 1200 );
670 }
671
672 return $this->get_posts( array_keys( $post_views ), $count, $types );
673 }
674
675 /**
676 * Filter the number of days used to calculate Top Posts for the Top Posts widget.
677 * We do not recommend accessing more than 10 days of results at one.
678 * When more than 10 days of results are accessed at once, results should be cached via the WordPress transients API.
679 * Querying for -1 days will give results for an infinite number of days.
680 *
681 * @module widgets
682 *
683 * @since 3.9.3
684 *
685 * @param int 2 Number of days. Default is 2.
686 * @param array $args The widget arguments.
687 */
688 $days = (int) apply_filters( 'jetpack_top_posts_days', 2, $args );
689
690 /** Handling situations where the number of days makes no sense - allows for unlimited days where $days = -1 */
691 if ( 0 === $days || false === $days ) {
692 $days = 2;
693 }
694
695 $query_args = array(
696 'max' => 11,
697 'summarize' => 1,
698 'num' => (int) $days,
699 );
700 $post_view_posts = convert_stats_array_to_object( ( new WPCOM_Stats() )->get_top_posts( $query_args ) );
701
702 if ( ! isset( $post_view_posts->summary ) || empty( $post_view_posts->summary->postviews ) ) {
703 return array();
704 }
705
706 $post_view_ids = array_filter( wp_list_pluck( $post_view_posts->summary->postviews, 'id' ) );
707
708 if ( ! $post_view_ids ) {
709 return array();
710 }
711
712 return $this->get_posts( $post_view_ids, $count, $types );
713 }
714
715 /**
716 * Get some posts if no posts are found in the stats API
717 *
718 * @since 8.4.0 Added $count and $types
719 *
720 * @param int $count The maximum number of posts to be returned.
721 * @param array $types The post types that should be returned.
722 * @return array
723 */
724 public function get_fallback_posts( $count = 10, $types = array( 'post', 'page' ) ) {
725 $post_query = new WP_Query();
726
727 if ( ! is_array( $types ) || empty( $types ) ) {
728 $types = array( 'post', 'page' );
729 }
730
731 $posts = $post_query->query(
732 array(
733 'posts_per_page' => $count,
734 'post_status' => 'publish',
735 'post_type' => $types,
736 'no_found_rows' => true,
737 'fields' => 'ids',
738 )
739 );
740
741 if ( ! $posts ) {
742 return array();
743 }
744
745 return $this->get_posts( $posts, $count, $types );
746 }
747
748 /**
749 * Get posts from an array of IDs
750 *
751 * @since 8.4.0 Added $types parameters
752 *
753 * @param array $post_ids The post IDs.
754 * @param int $count The maximum number of posts to return.
755 * @param array $types The post types that should be returned. Optional. Defaults to 'post', 'page'.
756 * @return array
757 */
758 public function get_posts( $post_ids, $count, $types = array( 'post', 'page' ) ) {
759 $counter = 0;
760
761 if ( ! is_array( $types ) || empty( $types ) ) {
762 $types = array( 'post', 'page' );
763 }
764
765 $posts = array();
766 foreach ( (array) $post_ids as $post_id ) {
767 $post = get_post( $post_id );
768
769 if ( ! $post ) {
770 continue;
771 }
772
773 /**
774 * Attachment pages use the 'inherit' post status by default.
775 * To be able to remove attachment pages from private and password protect posts,
776 * we need to replace their post status by the parent post' status.
777 */
778 if ( 'inherit' === $post->post_status && 'attachment' === $post->post_type ) {
779 $post->post_status = get_post_status( $post_id );
780 }
781
782 // hide private and password protected posts.
783 if ( 'publish' !== $post->post_status || ! empty( $post->post_password ) ) {
784 continue;
785 }
786
787 // Filter by chosen Post Types.
788 if ( ! in_array( $post->post_type, $types, true ) ) {
789 continue;
790 }
791
792 // Both get HTML stripped etc on display.
793 if ( empty( $post->post_title ) ) {
794 $title_source = $post->post_content;
795 $title = wp_html_excerpt( $title_source, 50 );
796 $title .= '&hellip;';
797 } else {
798 $title = $post->post_title;
799 }
800
801 $permalink = get_permalink( $post->ID );
802
803 $post_type = $post->post_type;
804
805 $posts[] = compact( 'title', 'permalink', 'post_id', 'post_type' );
806 ++$counter;
807
808 if ( $counter == $count ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
809 break; // only need to load and show x number of likes.
810 }
811 }
812
813 /**
814 * Filter the Top Posts and Pages.
815 *
816 * @module widgets
817 *
818 * @since 3.0.0
819 *
820 * @param array $posts Array of the most popular posts.
821 * @param array $post_ids Array of Post IDs.
822 * @param string $count Number of Top Posts we want to display.
823 */
824 return apply_filters( 'jetpack_widget_get_top_posts', $posts, $post_ids, $count );
825 }
826 }
827
828 /**
829 * Create a shortcode to display the widget anywhere.
830 *
831 * @since 3.9.2
832 *
833 * @param array $instance Saved values from database.
834 */
835 function jetpack_do_top_posts_widget( $instance ) {
836 // Post Types can't be entered as an array in the shortcode parameters.
837 if ( isset( $instance['types'] ) && is_string( $instance['types'] ) ) {
838 $instance['types'] = explode( ',', $instance['types'] );
839 }
840
841 $instance = shortcode_atts(
842 Jetpack_Top_Posts_Widget::defaults(),
843 $instance,
844 'jetpack_top_posts_widget'
845 );
846
847 // Add a class to allow styling.
848 $args = array(
849 'before_widget' => sprintf( '<div class="%s">', 'jetpack_top_posts_widget' ),
850 );
851
852 ob_start();
853 the_widget( 'Jetpack_Top_Posts_Widget', $instance, $args );
854 $output = ob_get_clean();
855
856 return $output;
857 }
858 add_shortcode( 'jetpack_top_posts_widget', 'jetpack_do_top_posts_widget' );
859