Skip to content

Commit 73c0f11

Browse files
committed
jetpack-mu-wpcom: Add comment like caching and only send requests when module active
1 parent ffeb1af commit 73c0f11

File tree

1 file changed

+208
-93
lines changed

1 file changed

+208
-93
lines changed
Lines changed: 208 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?php
1+
<?php // phpcs:ignore
22
/**
33
* Plugin Name: Jetpack MU WPCom Comment Likes
44
* Description: Adds a "Like" action to comment rows and enqueues the necessary assets in the admin area.
@@ -11,112 +11,227 @@
1111
}
1212

1313
/**
14-
* Adds a "liked" class to comments that the current user has liked.
15-
*
16-
* @param array $classes Array of comment classes.
17-
* @param string $css_class Unused.
18-
* @param int $comment_id The comment ID.
19-
* @return array Modified array of comment classes.
14+
* WPCom Comments Likes functionality in a singleton pattern.
2015
*/
21-
function wpcom_comments_add_like_class( $classes, $css_class, $comment_id ) {
22-
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
23-
$blog_id = get_current_blog_id();
24-
$liked = Likes::comment_like_current_user_likes( $blog_id, $comment_id );
25-
} else {
26-
$blog_id = Jetpack_Options::get_option( 'id' );
27-
$response = Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user(
28-
"/sites/$blog_id/comments/$comment_id/likes",
29-
'v1.1',
30-
array( 'method' => 'GET' ),
31-
null,
32-
'rest'
33-
);
16+
class WPCom_Comments_Likes {
17+
const CACHE_EXPIRATION = HOUR_IN_SECONDS;
18+
19+
/**
20+
* Singleton instance.
21+
*
22+
* @var WPCom_Comments_Likes
23+
*/
24+
private static $instance = null;
25+
26+
/**
27+
* Flag to track if hooks have been initialized.
28+
*
29+
* @var bool
30+
*/
31+
private $initialized = false;
3432

35-
// If the request fails, simply return the unmodified classes.
36-
if ( is_wp_error( $response ) ) {
37-
return $classes;
33+
/**
34+
* Private constructor to prevent direct instantiation.
35+
*/
36+
private function __construct() {
37+
// Register REST API for Atomic sites.
38+
if ( defined( 'IS_ATOMIC' ) && IS_ATOMIC ) {
39+
add_action( 'rest_api_init', array( $this, 'register_like_api' ) );
3840
}
3941

40-
$response_data = json_decode( wp_remote_retrieve_body( $response ), true );
42+
add_action( 'admin_init', array( $this, 'init' ) );
43+
}
44+
45+
/**
46+
* Get the singleton instance.
47+
*
48+
* @return WPCom_Comments_Likes
49+
*/
50+
public static function get_instance() {
51+
if ( null === self::$instance ) {
52+
self::$instance = new self();
53+
}
54+
return self::$instance;
55+
}
4156

42-
// If the response doesn't include 'i_like', don't add the class.
43-
if ( empty( $response_data['i_like'] ) ) {
44-
return $classes;
57+
/**
58+
* Initialize the comment likes functionality if enabled.
59+
*/
60+
public function init() {
61+
// Only initialize if comment likes are enabled.
62+
if ( ! $this->is_comment_likes_enabled() ) {
63+
return;
4564
}
4665

47-
$liked = $response_data['i_like'];
66+
if ( is_admin() ) {
67+
add_filter( 'comment_class', array( $this, 'add_like_class' ), 10, 3 );
68+
add_filter( 'comment_row_actions', array( $this, 'enable_likes' ), 10, 2 );
69+
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 10, 2 );
70+
}
4871
}
4972

50-
// Append the 'liked' class if the comment is liked.
51-
if ( $liked ) {
52-
$classes[] = 'liked';
73+
/**
74+
* Check if comment likes are enabled.
75+
*
76+
* This is currently only expected to work for WoW sites.
77+
*
78+
* @return bool True if comment likes are enabled, false otherwise.
79+
*/
80+
private function is_comment_likes_enabled() {
81+
// @phan-suppress-next-line PhanUndeclaredClassReference
82+
if ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'is_module_active' ) ) {
83+
// @phan-suppress-next-line PhanUndeclaredClassMethod
84+
return Jetpack::is_module_active( 'comment-likes' );
85+
}
86+
87+
return false;
5388
}
5489

55-
return $classes;
56-
}
57-
add_filter( 'comment_class', 'wpcom_comments_add_like_class', 10, 3 );
90+
/**
91+
* Get cache key for comment like status.
92+
*
93+
* @param int $comment_id The comment ID.
94+
* @param int $user_id The user ID.
95+
* @return string The cache key.
96+
*/
97+
private function get_cache_key( $comment_id, $user_id ) {
98+
return "comment_like_{$comment_id}_{$user_id}";
99+
}
58100

59-
/**
60-
* Adds "Like" and "Unlike" action buttons to comment rows.
61-
*
62-
* @param array $actions Array of actions for the comment.
63-
* @param WP_Comment $comment The comment object.
64-
* @return array Modified actions array.
65-
*/
66-
function wpcom_comments_enable_likes( $actions, $comment ) {
67-
$actions['like'] = sprintf(
68-
'<button class="button-link comment-like-button" data-comment-id="%d" aria-label="%s">%s</button>',
69-
$comment->comment_ID,
70-
esc_attr__( 'Like this comment', 'jetpack-mu-wpcom' ),
71-
esc_html__( 'Like', 'jetpack-mu-wpcom' )
72-
);
73-
74-
$actions['unlike'] = sprintf(
75-
'<button class="button-link comment-unlike-button" data-comment-id="%d" aria-label="%s">%s</button>',
76-
$comment->comment_ID,
77-
esc_attr__( 'Unlike this comment', 'jetpack-mu-wpcom' ),
78-
esc_html__( 'Liked by you', 'jetpack-mu-wpcom' )
79-
);
80-
81-
return $actions;
82-
}
83-
add_filter( 'comment_row_actions', 'wpcom_comments_enable_likes', 10, 2 );
101+
/**
102+
* Do a comment like API request.
103+
*
104+
* @param int $blog_id The blog ID.
105+
* @param int $user_id The user ID.
106+
* @param int $comment_id The comment ID.
107+
* @return bool|WP_Error True if the comment is liked, false otherwise, or a WP_Error if the request fails.
108+
*/
109+
private function do_comment_like_api_request( $blog_id, $user_id, $comment_id ) {
110+
$cache_key = $this->get_cache_key( $comment_id, $user_id );
84111

85-
/**
86-
* Enqueues the comment like assets (JavaScript and CSS) on the Edit Comments screen.
87-
*
88-
* @param string $hook The current admin page hook.
89-
*/
90-
function wpcom_enqueue_comment_like_script( $hook ) {
91-
// Only enqueue assets on the edit-comments screen.
92-
if ( 'edit-comments.php' !== $hook ) {
93-
return;
112+
$cached_result = get_transient( $cache_key );
113+
114+
if ( false !== $cached_result ) {
115+
$liked = $cached_result;
116+
} else {
117+
$response = Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user(
118+
"/sites/$blog_id/comments/$comment_id/likes",
119+
'v1.1',
120+
array( 'method' => 'GET' ),
121+
null,
122+
'rest'
123+
);
124+
125+
// If the request fails, simply return the unmodified classes.
126+
if ( is_wp_error( $response ) ) {
127+
return $response;
128+
}
129+
130+
$response_data = json_decode( wp_remote_retrieve_body( $response ), true );
131+
132+
$liked = empty( $response_data['i_like'] ) ? 'no' : 'yes';
133+
134+
// Cache the result.
135+
set_transient( $cache_key, $liked, self::CACHE_EXPIRATION );
136+
}
137+
138+
return $liked;
94139
}
95140

96-
// Enqueue the assets using the Jetpack MU WPCom helper function.
97-
jetpack_mu_wpcom_enqueue_assets( 'wpcom-comment-like', array( 'js', 'css' ) );
98-
99-
// Localize the script with error messages.
100-
wp_localize_script(
101-
'jetpack-mu-wpcom-wpcom-comment-like',
102-
'wpcomCommentLikesData',
103-
array(
104-
'post_like_error' => __( 'Something went wrong when attempting to like that comment. Please try again.', 'jetpack-mu-wpcom' ),
105-
'post_unlike_error' => __( 'Something went wrong when attempting to unlike that comment. Please try again.', 'jetpack-mu-wpcom' ),
106-
'dismiss_notice_text' => __( 'Dismiss this notice', 'jetpack-mu-wpcom' ),
107-
)
108-
);
109-
}
110-
add_action( 'admin_enqueue_scripts', 'wpcom_enqueue_comment_like_script', 10, 2 );
141+
/**
142+
* Adds a "liked" class to comments that the current user has liked.
143+
*
144+
* @param array $classes Array of comment classes.
145+
* @param string $css_class Unused.
146+
* @param int $comment_id The comment ID.
147+
* @return array Modified array of comment classes.
148+
*/
149+
public function add_like_class( $classes, $css_class, $comment_id ) {
150+
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
151+
$blog_id = get_current_blog_id();
152+
$liked = Likes::comment_like_current_user_likes( $blog_id, $comment_id );
153+
} else {
154+
$blog_id = Jetpack_Options::get_option( 'id' );
155+
$user_id = get_current_user_id();
111156

112-
/**
113-
* Register an API to handle Likes on Atomic sites.
114-
*/
115-
function wpcom_comments_register_like_api() {
116-
require_once __DIR__ . '/class-wp-rest-comment-like.php';
117-
$controller = new WP_REST_Comment_Like();
118-
$controller->register_routes();
119-
}
120-
if ( defined( 'IS_ATOMIC' ) && IS_ATOMIC ) {
121-
add_action( 'rest_api_init', 'wpcom_comments_register_like_api' );
157+
$liked = $this->do_comment_like_api_request( $blog_id, $user_id, $comment_id );
158+
159+
if ( is_wp_error( $liked ) ) {
160+
return $classes;
161+
}
162+
163+
// We use 'yes' and 'no' when we store the transient to minimize unexpected casting.
164+
// So, we cast to boolean here.
165+
$liked = 'yes' === $liked;
166+
}
167+
168+
// Append the 'liked' class if the comment is liked.
169+
if ( $liked ) {
170+
$classes[] = 'liked';
171+
}
172+
173+
return $classes;
174+
}
175+
176+
/**
177+
* Adds "Like" and "Unlike" action buttons to comment rows.
178+
*
179+
* @param array $actions Array of actions for the comment.
180+
* @param WP_Comment $comment The comment object.
181+
* @return array Modified actions array.
182+
*/
183+
public function enable_likes( $actions, $comment ) {
184+
$actions['like'] = sprintf(
185+
'<button class="button-link comment-like-button" data-comment-id="%d" aria-label="%s">%s</button>',
186+
$comment->comment_ID,
187+
esc_attr__( 'Like this comment', 'jetpack-mu-wpcom' ),
188+
esc_html__( 'Like', 'jetpack-mu-wpcom' )
189+
);
190+
191+
$actions['unlike'] = sprintf(
192+
'<button class="button-link comment-unlike-button" data-comment-id="%d" aria-label="%s">%s</button>',
193+
$comment->comment_ID,
194+
esc_attr__( 'Unlike this comment', 'jetpack-mu-wpcom' ),
195+
esc_html__( 'Liked by you', 'jetpack-mu-wpcom' )
196+
);
197+
198+
return $actions;
199+
}
200+
201+
/**
202+
* Enqueues the comment like assets (JavaScript and CSS) on the Edit Comments screen.
203+
*
204+
* @param string $hook The current admin page hook.
205+
*/
206+
public function enqueue_scripts( $hook ) {
207+
// Only enqueue assets on the edit-comments screen.
208+
if ( 'edit-comments.php' !== $hook ) {
209+
return;
210+
}
211+
212+
// Enqueue the assets using the Jetpack MU WPCom helper function.
213+
jetpack_mu_wpcom_enqueue_assets( 'wpcom-comment-like', array( 'js', 'css' ) );
214+
215+
// Localize the script with error messages.
216+
wp_localize_script(
217+
'jetpack-mu-wpcom-wpcom-comment-like',
218+
'wpcomCommentLikesData',
219+
array(
220+
'post_like_error' => __( 'Something went wrong when attempting to like that comment. Please try again.', 'jetpack-mu-wpcom' ),
221+
'post_unlike_error' => __( 'Something went wrong when attempting to unlike that comment. Please try again.', 'jetpack-mu-wpcom' ),
222+
'dismiss_notice_text' => __( 'Dismiss this notice', 'jetpack-mu-wpcom' ),
223+
)
224+
);
225+
}
226+
227+
/**
228+
* Register an API to handle Likes on Atomic sites.
229+
*/
230+
public function register_like_api() {
231+
require_once __DIR__ . '/class-wp-rest-comment-like.php';
232+
$controller = new WP_REST_Comment_Like();
233+
$controller->register_routes();
234+
}
122235
}
236+
237+
WPCom_Comments_Likes::get_instance();

0 commit comments

Comments
 (0)