Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 169 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 1 |
| jetpack_posts_i_like_widget_init | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| Jetpack_Posts_I_Like_Widget | |
0.00% |
0 / 167 |
|
0.00% |
0 / 8 |
1892 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
| enqueue_style | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| enqueue_script | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| form | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
56 | |||
| update | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
56 | |||
| widget | |
0.00% |
0 / 67 |
|
0.00% |
0 / 1 |
306 | |||
| get_liked_posts | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
42 | |||
| get_local_user_from_wpcom_user | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php // phpcs:ignore Squiz.Commenting.FileComment.Missing |
| 2 | |
| 3 | /** |
| 4 | * Posts I Like Widget |
| 5 | */ |
| 6 | class Jetpack_Posts_I_Like_Widget extends WP_Widget { |
| 7 | /** |
| 8 | * Widget settings. |
| 9 | * |
| 10 | * @var array $defaults |
| 11 | */ |
| 12 | public $defaults = array(); |
| 13 | |
| 14 | /** |
| 15 | * Registers the widget with WordPress. |
| 16 | */ |
| 17 | public function __construct() { |
| 18 | parent::__construct( |
| 19 | 'jetpack_posts_i_like', // Base ID |
| 20 | __( 'Posts I Like', 'wpcomsh' ), // Name |
| 21 | array( |
| 22 | 'description' => __( 'A list of the posts I most recently liked', 'wpcomsh' ), |
| 23 | ) |
| 24 | ); |
| 25 | |
| 26 | $this->defaults = array( |
| 27 | 'title' => __( 'Posts I Like', 'wpcomsh' ), |
| 28 | 'liker' => 0, |
| 29 | 'number' => 5, |
| 30 | 'display' => 'list', |
| 31 | ); |
| 32 | |
| 33 | if ( is_active_widget( false, false, $this->id_base ) || is_active_widget( false, false, 'monster' ) ) { |
| 34 | add_action( 'wp_print_styles', array( $this, 'enqueue_style' ) ); |
| 35 | add_action( 'wp_print_scripts', array( $this, 'enqueue_script' ) ); |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | /** |
| 40 | * Enqueue style. |
| 41 | */ |
| 42 | public function enqueue_style() { |
| 43 | wp_enqueue_style( 'widget-grid-and-list' ); |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * Enqueue script. |
| 48 | */ |
| 49 | public function enqueue_script() { |
| 50 | wp_enqueue_script( 'widget-bump-view' ); |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * Back-end widget form. |
| 55 | * |
| 56 | * @see WP_Widget::form() |
| 57 | * |
| 58 | * @param array $instance Previously saved values from database. |
| 59 | * @return never |
| 60 | */ |
| 61 | public function form( $instance ) { |
| 62 | // outputs the options form on admin |
| 63 | $instance = array_merge( $this->defaults, $instance ); |
| 64 | |
| 65 | $title = $instance['title']; |
| 66 | $number = (int) $instance['number']; |
| 67 | |
| 68 | if ( $number < 1 ) { |
| 69 | $number = 1; |
| 70 | } elseif ( $number > 15 ) { |
| 71 | $number = 15; |
| 72 | } |
| 73 | |
| 74 | $liker = $instance['liker']; |
| 75 | // If the liker is a wpcom user, convert it into a local user. |
| 76 | if ( empty( $instance['local_liker'] ) ) { |
| 77 | $liker = self::get_local_user_from_wpcom_user( $liker ); |
| 78 | } |
| 79 | if ( 0 === $liker ) { |
| 80 | $liker = get_current_user_id(); |
| 81 | } |
| 82 | |
| 83 | $display = ( 'grid' === $instance['display'] ) ? 'grid' : 'list'; |
| 84 | |
| 85 | ?> |
| 86 | <p> |
| 87 | <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'wpcomsh' ); ?></label> |
| 88 | <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 ); ?>" /> |
| 89 | </p> |
| 90 | |
| 91 | <p> |
| 92 | <label for="<?php echo esc_attr( $this->get_field_id( 'number' ) ); ?>"><?php esc_html_e( 'Number of posts to show (1 to 15):', 'wpcomsh' ); ?></label> |
| 93 | <input id="<?php echo esc_attr( $this->get_field_id( 'number' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'number' ) ); ?>" type="number" value="<?php echo esc_attr( (string) $number ); ?>" min="1" max="15" /> |
| 94 | </p> |
| 95 | |
| 96 | <p> |
| 97 | <label><?php esc_html_e( 'Display as:', 'wpcomsh' ); ?></label> |
| 98 | <ul> |
| 99 | <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( 'List', 'wpcomsh' ); ?></label></li> |
| 100 | <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( 'Grid', 'wpcomsh' ); ?></label></li> |
| 101 | </ul> |
| 102 | </p> |
| 103 | <?php |
| 104 | |
| 105 | $liker_dropdown = wp_dropdown_users( |
| 106 | array( |
| 107 | 'selected' => $liker, |
| 108 | 'name' => $this->get_field_name( 'liker' ), |
| 109 | 'id' => $this->get_field_id( 'liker' ), |
| 110 | 'echo' => false, |
| 111 | 'hide_if_only_one_author' => true, |
| 112 | ) |
| 113 | ); |
| 114 | |
| 115 | if ( $liker_dropdown ) : |
| 116 | ?> |
| 117 | <p> |
| 118 | <label for="<?php echo esc_attr( $this->get_field_id( 'liker' ) ); ?>"><?php esc_html_e( "Author's likes to display:", 'wpcomsh' ); ?></label> |
| 119 | <?php echo $liker_dropdown; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- as this is HTML code from core's wp_dropdown_users() */ ?> |
| 120 | </p> |
| 121 | <?php else : ?> |
| 122 | <input type="hidden" |
| 123 | id="<?php echo esc_attr( $this->get_field_id( 'liker' ) ); ?>" |
| 124 | name="<?php echo esc_attr( $this->get_field_name( 'liker' ) ); ?>" |
| 125 | value="<?php echo (int) $liker; ?>" |
| 126 | /> |
| 127 | <?php |
| 128 | endif; |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * Sanitize widget form values as they are saved. |
| 133 | * |
| 134 | * @see WP_Widget::update() |
| 135 | * |
| 136 | * @param array $new_instance Values just sent to be saved. |
| 137 | * @param array $old_instance Previously saved values from database. |
| 138 | * |
| 139 | * @return array Updated safe values to be saved. |
| 140 | */ |
| 141 | public function update( $new_instance, $old_instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
| 142 | // processes widget options to be saved |
| 143 | |
| 144 | $instance = array(); |
| 145 | $instance['title'] = wp_kses( $new_instance['title'], array() ); |
| 146 | if ( $instance['title'] === $this->defaults['title'] ) { |
| 147 | $instance['title'] = false; // Store as false in case of language change |
| 148 | } |
| 149 | |
| 150 | $instance['number'] = (int) $new_instance['number']; |
| 151 | if ( $instance['number'] < 1 ) { |
| 152 | $instance['number'] = 1; |
| 153 | } elseif ( $instance['number'] > 15 ) { |
| 154 | $instance['number'] = 15; |
| 155 | } |
| 156 | |
| 157 | $instance['display'] = isset( $new_instance['display'] ) && 'grid' === $new_instance['display'] ? 'grid' : 'list'; |
| 158 | |
| 159 | $instance['liker'] = (int) $new_instance['liker']; |
| 160 | if ( ! is_user_member_of_blog( $instance['liker'] ) ) { |
| 161 | $instance['liker'] = 0; |
| 162 | } |
| 163 | |
| 164 | $instance['local_liker'] = true; |
| 165 | |
| 166 | return $instance; |
| 167 | } |
| 168 | |
| 169 | /** |
| 170 | * Front-end display of widget. |
| 171 | * |
| 172 | * @see WP_Widget::widget() |
| 173 | * |
| 174 | * @param array $args Widget arguments. |
| 175 | * @param array $instance Saved values from database. |
| 176 | */ |
| 177 | public function widget( $args, $instance ) { |
| 178 | // Set default values to avoid displaying undeinfed index notices |
| 179 | $instance = array_merge( $this->defaults, $instance ); |
| 180 | $title = apply_filters( 'widget_title', $instance['title'] ); |
| 181 | |
| 182 | /** |
| 183 | * Use the Like's API to load all of a user's ($instance['liker']) likes |
| 184 | * and put them all in a posts_i_like array so we can easily output it based on grid or list |
| 185 | */ |
| 186 | $liker = $instance['liker'] ?? null; |
| 187 | $number_to_display = $instance['number']; |
| 188 | |
| 189 | $get_image_options = array( |
| 190 | 'from_html' => true, |
| 191 | 'fallback_to_avatars' => true, |
| 192 | 'gravatar_default' => 'https://s0.wp.com/i/logo/white-gray-80.png', |
| 193 | ); |
| 194 | |
| 195 | if ( 'grid' === $instance['display'] ) { |
| 196 | // for grid display, we need an even number so it looks ok |
| 197 | $number_to_display += $number_to_display % 2; |
| 198 | $get_image_options['avatar_size'] = 200; |
| 199 | } else { |
| 200 | $get_image_options['avatar_size'] = 40; |
| 201 | } |
| 202 | |
| 203 | // If the liker is a wpcom user, convert it into a local user. |
| 204 | if ( $liker && empty( $instance['local_liker'] ) ) { |
| 205 | $liker = self::get_local_user_from_wpcom_user( $liker ); |
| 206 | } |
| 207 | |
| 208 | $posts_i_like = array(); |
| 209 | if ( $liker && is_user_member_of_blog( $liker ) ) { |
| 210 | $force_update = is_customize_preview(); |
| 211 | $posts = $this->get_liked_posts( $liker, $number_to_display, $force_update ); |
| 212 | |
| 213 | foreach ( $posts as $post ) { |
| 214 | $posts_i_like[] = (object) $post; |
| 215 | } |
| 216 | |
| 217 | do_action( 'jetpack_stats_extra', 'widget_view', 'posts_i_like' ); |
| 218 | } |
| 219 | |
| 220 | $current_user_controls_widget = ( is_user_logged_in() && get_current_user_id() === $liker ) || current_user_can( 'edit_theme_options' ); |
| 221 | if ( ! $posts_i_like ) { |
| 222 | // Bail if There are no likes and the current user can do nothing about it. |
| 223 | if ( ! $current_user_controls_widget ) { |
| 224 | return; |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 229 | |
| 230 | if ( ! empty( $title ) ) { |
| 231 | echo $args['before_title'] . esc_html( $title ) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 232 | } |
| 233 | |
| 234 | if ( $posts_i_like ) { |
| 235 | if ( 'grid' === $instance['display'] ) { |
| 236 | $output = ''; |
| 237 | |
| 238 | echo "<div class='widgets-grid-layout no-grav'>"; |
| 239 | |
| 240 | foreach ( $posts_i_like as $post ) { |
| 241 | $hover_text = sprintf( |
| 242 | /* translators: %1$s is the post title, %1$s is the blog name. */ |
| 243 | _x( '%1$s on %2$s', '1: Post Title, 2: Blog Name', 'wpcomsh' ), |
| 244 | wp_kses( $post->post_title, array() ), |
| 245 | wp_kses( $post->blog_name, array() ) |
| 246 | ); |
| 247 | |
| 248 | $output .= "<div class='widget-grid-view-image'>"; |
| 249 | $output .= "<a href='" . esc_url( $post->post_permalink ) . "' title='" . esc_attr( $hover_text ) . "' class='bump-view' data-bump-view='pil'>"; |
| 250 | $output .= "<img src='" . esc_url( $post->post_image ) . "'/>"; |
| 251 | $output .= '</a>'; |
| 252 | $output .= '</div>'; |
| 253 | } |
| 254 | |
| 255 | echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- as this is intentially complex HTML and the vars have been escaped already. |
| 256 | |
| 257 | echo '</div>'; |
| 258 | |
| 259 | } else { |
| 260 | echo "<ul class='widgets-list-layout no-grav'>"; |
| 261 | |
| 262 | foreach ( $posts_i_like as $post ) { |
| 263 | echo '<li>'; |
| 264 | echo "<img src='" . esc_url( $post->post_image ) . "' class='widgets-list-layout-blavatar' />"; |
| 265 | echo "<div class='widgets-list-layout-links'><a href='" . esc_url( $post->post_permalink ) . "' class='bump-view' data-bump-view='pil'>" . esc_html( $post->post_title ) . '</a> '; |
| 266 | echo '<span>' . esc_html__( 'on', 'wpcomsh' ); |
| 267 | echo " <a href='" . esc_url( $post->blog_url ) . "' class='bump-view' data-bump-view='pil'>" . esc_html( $post->blog_name ) . '</a>'; |
| 268 | echo '</span></div>'; |
| 269 | echo '</li>'; |
| 270 | } |
| 271 | |
| 272 | echo '</ul>'; |
| 273 | } |
| 274 | } elseif ( $current_user_controls_widget ) { |
| 275 | echo '<p>' . sprintf( |
| 276 | wp_kses( |
| 277 | // translators: %s is a URL to the widgets settings page. |
| 278 | __( 'You have not recently liked any posts. Once you do, this <a href="%s">Posts I Like</a> widget will display them.', 'wpcomsh' ), |
| 279 | array( |
| 280 | 'a' => array( 'href' => array() ), |
| 281 | ) |
| 282 | ), |
| 283 | esc_url( admin_url( 'widgets.php' ) ) |
| 284 | ) . '</p>'; |
| 285 | } |
| 286 | |
| 287 | echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 288 | } |
| 289 | |
| 290 | /** |
| 291 | * Gets posts that are marked as liked. |
| 292 | * |
| 293 | * @param int $user_id User ID. |
| 294 | * @param int $post_count Count of posts to retrieve. |
| 295 | * @param bool $force_update Whether or not to use cached results if available. |
| 296 | */ |
| 297 | public function get_liked_posts( $user_id, $post_count = 5, $force_update = false ) { |
| 298 | $transient_key = implode( '|', array( 'wpcomsh-post-i-like-widget', $user_id, $post_count ) ); |
| 299 | |
| 300 | if ( ! $force_update ) { |
| 301 | $posts = get_transient( $transient_key ); |
| 302 | |
| 303 | if ( false !== $posts ) { |
| 304 | return $posts; |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | $version = 2; |
| 309 | $path = 'liked-posts'; |
| 310 | |
| 311 | $args = array( |
| 312 | 'url' => sprintf( '%s/wpcom/v%s/%s?count=%s', JETPACK__WPCOM_JSON_API_BASE, $version, $path, $post_count ), |
| 313 | 'method' => 'GET', |
| 314 | 'user_id' => $user_id, |
| 315 | 'blog_id' => (int) Jetpack_Options::get_option( 'id' ), |
| 316 | ); |
| 317 | |
| 318 | $response = Automattic\Jetpack\Connection\Client::remote_request( $args ); |
| 319 | |
| 320 | if ( is_wp_error( $response ) || 200 !== $response['response']['code'] || empty( $response['body'] ) ) { |
| 321 | return array(); |
| 322 | } |
| 323 | |
| 324 | $posts = json_decode( $response['body'], true ); |
| 325 | set_transient( $transient_key, $posts, 20 * MINUTE_IN_SECONDS ); |
| 326 | |
| 327 | return $posts; |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Get local user id from wpcom user id. |
| 332 | * |
| 333 | * @param int $user_id wpcom user id. |
| 334 | * @return int local user id that connected to the passed wpcom user id. Returns 0 if no result is found. |
| 335 | */ |
| 336 | public static function get_local_user_from_wpcom_user( $user_id ) { |
| 337 | global $wpdb; |
| 338 | |
| 339 | return (int) $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching |
| 340 | $wpdb->prepare( |
| 341 | "SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key=%s AND meta_value=%s", |
| 342 | 'wpcom_user_id', |
| 343 | $user_id |
| 344 | ) |
| 345 | ); |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | /** |
| 350 | * Register the widget for use in Appearance -> Widgets |
| 351 | */ |
| 352 | function jetpack_posts_i_like_widget_init() { // phpcs:ignore Universal.Files.SeparateFunctionsFromOO.Mixed |
| 353 | register_widget( 'Jetpack_Posts_I_Like_Widget' ); |
| 354 | } |
| 355 | add_action( 'widgets_init', 'jetpack_posts_i_like_widget_init' ); |