PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.0
Defender Security – Malware Scanner, Login Security & Firewall v6.2.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / audit / class-comment-audit.php

class-comment-audit.php in Defender Security – Malware Scanner, Login Security & Firewall 6.2.0, at src/component/audit/class-comment-audit.php

350 lines 13.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles the auditing of comment-related actions within WordPress.
4 *
5 * @package WP_Defender\Component\Audit
6 */
7
8 namespace WP_Defender\Component\Audit;
9
10 use WP_Defender\Traits\User;
11 use WP_Defender\Model\Audit_Log;
12
13 /**
14 * Handles various comment-related actions and provides methods for processing and generating audit log messages.
15 */
16 class Comment_Audit extends Audit_Event {
17
18 use User;
19
20 public const ACTION_SPAMMED = 'spammed', ACTION_UNSPAMMED = 'unspammed', ACTION_DUPLICATED = 'duplicated',
21 ACTION_FLOOD = 'flood', ACTION_ADDED = 'added';
22 public const CONTEXT_COMMENT = 'ct_comment';
23
24 /**
25 * Defines and returns an array of WordPress hooks that this class will handle.
26 * Each hook is associated with an event type, action type, and a callback method.
27 * The method specifies how the event is processed when the hook is triggered.
28 *
29 * @return array An associative array where each key is a WordPress hook and each value is an array detailing the
30 * hook configuration.
31 */
32 public function get_hooks(): array {
33 return array(
34 'wp_insert_comment' => array(
35 'args' => array( 'comment_ID' ),
36 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
37 'action_type' => self::ACTION_ADDED,
38 'callback' => array( self::class, 'process_generic_comment' ),
39 ),
40 'comment_flood_trigger' => array(
41 'args' => array( 'time_lastcomment', 'time_newcomment' ),
42 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
43 'action_type' => self::ACTION_FLOOD,
44 'context' => self::CONTEXT_COMMENT,
45 'text' => sprintf(
46 /* translators: 1: Blog name, 2: Source of action. For e.g. Hub or a logged-in user */
47 esc_html__( '%1$s User %2$s flooded comment', 'defender-security' ),
48 '{{blog_name}}',
49 '{{wp_user}}'
50 ),
51 ),
52 'deleted_comment' => array(
53 'args' => array( 'comment_ID' ),
54 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
55 'action_type' => self::ACTION_DELETED,
56 'callback' => array( self::class, 'process_generic_comment' ),
57 ),
58 'trash_comment' => array(
59 'args' => array( 'comment_ID' ),
60 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
61 'action_type' => self::ACTION_TRASHED,
62 'callback' => array( self::class, 'process_generic_comment' ),
63 ),
64 'untrash_comment' => array(
65 'args' => array( 'comment_ID' ),
66 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
67 'action_type' => self::ACTION_RESTORED,
68 'callback' => array( self::class, 'process_generic_comment' ),
69 ),
70 'spam_comment' => array(
71 'args' => array( 'comment_ID' ),
72 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
73 'action_type' => self::ACTION_SPAMMED,
74 'callback' => array( self::class, 'process_generic_comment' ),
75 ),
76 'unspam_comment' => array(
77 'args' => array( 'comment_ID' ),
78 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
79 'action_type' => self::ACTION_UNSPAMMED,
80 'callback' => array( self::class, 'process_generic_comment' ),
81 ),
82 'transition_comment_status' => array(
83 'args' => array( 'new_status', 'old_status', 'comment' ),
84 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
85 'action_type' => self::ACTION_UPDATED,
86 'callback' => array(
87 self::class,
88 'process_comment_status_changed',
89 ),
90 ),
91 'edit_comment' => array(
92 'args' => array( 'comment_ID' ),
93 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
94 'action_type' => self::ACTION_UPDATED,
95 'callback' => array( self::class, 'process_generic_comment' ),
96 ),
97 'comment_duplicate_trigger' => array(
98 'args' => array( 'commentdata' ),
99 'event_type' => Audit_Log::EVENT_TYPE_COMMENT,
100 'action_type' => self::ACTION_DUPLICATED,
101 'callback' => array(
102 self::class,
103 'process_comment_duplicate_trigger',
104 ),
105 ),
106 );
107 }
108
109 /**
110 * Provides a dictionary for mapping constant values to their respective display strings.
111 * This method is useful for translating coded values into human-readable text, primarily for display purposes.
112 *
113 * @return array An associative array where keys are constant identifiers and values are the translated strings.
114 */
115 public function dictionary(): array {
116 return array(
117 self::ACTION_DUPLICATED => esc_html__( 'Duplicated', 'defender-security' ),
118 self::ACTION_SPAMMED => esc_html__( 'Spammed', 'defender-security' ),
119 self::ACTION_UNSPAMMED => esc_html__( 'Unspammed', 'defender-security' ),
120 self::CONTEXT_COMMENT => esc_html__( 'Comment', 'defender-security' ),
121 );
122 }
123
124 /**
125 * Processes the event when a duplicate comment is detected.
126 * This method constructs a message detailing the duplicate comment event, including information about the comment,
127 * the post, and the user involved.
128 *
129 * @return array An array containing the formatted message string and the post type label.
130 */
131 public function process_comment_duplicate_trigger(): array {
132 $args = func_get_args();
133 $comment_data = $args[1]['commentdata'];
134
135 $post = get_post( $comment_data['comment_post_ID'] );
136 $post_type = get_post_type_object( $post->post_type );
137 $post_type_label = strtolower( $post_type->labels->singular_name );
138 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
139 $text = sprintf(
140 /* translators: 1: Blog name, 2: Comment author, 3: Post type, 4: Post title */
141 esc_html__( '%1$s User %2$s submitted a duplicate comment on %3$s "%4$s"', 'defender-security' ),
142 $blog_name,
143 is_user_logged_in() ? $this->get_user_display( get_current_user_id() ) : $comment_data['comment_author'],
144 $post_type_label,
145 $post->post_title
146 );
147
148 return array( $text, $post_type_label );
149 }
150
151 /**
152 * Handles changes in comment status, such as from unapproved to approved.
153 * This method constructs a message that details the change in status of a comment, including information about the
154 * comment, the post, and the user involved.
155 *
156 * @return array An array containing the formatted message string and the post type label.
157 */
158 public function process_comment_status_changed(): array {
159 $args = func_get_args();
160 $new_stat = $args[1]['new_status'];
161 $old_stat = $args[1]['old_status'];
162 $comment = $args[1]['comment'];
163 $post = get_post( $comment->comment_post_ID );
164 $post_type = get_post_type_object( $post->post_type );
165 $post_type_label = strtolower( $post_type->labels->singular_name );
166 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
167 $text = false;
168 if ( 'unapproved' === $old_stat && 'approved' === $new_stat ) {
169 $text = sprintf(
170 /* translators: 1: Blog name, 2: User's display name, 3: Comment ID, 4: Comment author, 5: Post type, 6: Post title */
171 esc_html__( '%1$s %2$s approved comment ID %3$s from %4$s, on %5$s "%6$s"', 'defender-security' ),
172 $blog_name,
173 $this->get_user_display( get_current_user_id() ),
174 $comment->comment_ID,
175 $comment->comment_author,
176 $post_type_label,
177 $post->post_title
178 );
179 } elseif ( 'unapproved' === $new_stat && 'approved' === $old_stat ) {
180 $text = sprintf(
181 /* translators: 1: Blog name, 2: User's display name, 3: Comment ID, 4: Comment author, 5: Post type, 6: Post title */
182 esc_html__( '%1$s %2$s unapproved comment ID %3$s from %4$s, on %5$s "%6$s"', 'defender-security' ),
183 $blog_name,
184 $this->get_user_display( get_current_user_id() ),
185 $comment->comment_ID,
186 $comment->comment_author,
187 $post_type_label,
188 $post->post_title
189 );
190 }
191
192 return array( $text, $post_type_label );
193 }
194
195 /**
196 * Generic handler for comment-related actions such as insertion, deletion, and editing.
197 * This method determines the specific action taken (e.g., comment posted, deleted, trashed) and constructs a
198 * corresponding message.
199 *
200 * @return bool|array False if the comment data is not set or an array containing the formatted message string and
201 * the post type label if successful.
202 */
203 public function process_generic_comment() {
204 $args = func_get_args();
205 $hookname = $args[0];
206 $comment_id = $args[1]['comment_ID'];
207 if ( ! isset( $args[1]['commentdata'] ) ) {
208 $comment = get_comment( $comment_id );
209 if ( ! ( $comment instanceof \WP_Comment ) ) {
210 return false;
211 }
212 $comment = $comment->to_array();
213 } else {
214 $comment = $args[1]['commentdata'];
215 if ( ! is_array( $comment ) || array() === $comment ) {
216 return false;
217 }
218 }
219 if ( ! isset( $args[1]['comment_approved'] ) ) {
220 $comment_approved = '';
221 } else {
222 $comment_approved = $args[1]['comment_approved'];
223 }
224 $post = get_post( $comment['comment_post_ID'] );
225 $post_type = get_post_type_object( $post->post_type );
226 $post_type_label = strtolower( $post_type->labels->singular_name );
227 $blog_name = is_multisite() ? '[' . get_bloginfo( 'name' ) . ']' : '';
228 switch ( $hookname ) {
229 case 'comment_post':
230 case 'wp_insert_comment':
231 if ( 'spam' === $comment_approved ) {
232 $comment_status = 'spam';
233 } elseif ( 1 === $comment_approved ) {
234 $comment_status = esc_html__( 'approved', 'defender-security' );
235 } else {
236 $comment_status = esc_html__( 'pending approval', 'defender-security' );
237 }
238 if ( 0 === (int) $comment['comment_parent'] ) {
239 $text = sprintf(
240 /* translators: 1: Blog name, 2: Comment author, 3: Post type, 4: Post title, 5: Comment status */
241 esc_html__( '%1$s %2$s commented on %3$s "%4$s" - comment status: %5$s', 'defender-security' ),
242 $blog_name,
243 $comment['comment_author'],
244 $post_type_label,
245 $post->post_title,
246 $comment_status
247 );
248 } else {
249 $parent_comment = get_comment( $comment['comment_parent'] );
250 $text = sprintf(
251 /* translators: 1: Blog name, 2: Comment author, 3: Parent comment author, 4: Post type, 5: Post title, 6: Comment status */
252 esc_html__(
253 "%1\$s %2\$s replied to %3\$s's comment on %4\$s \"%5\$s\" - comment status: %6\$s",
254 'defender-security'
255 ),
256 $blog_name,
257 $comment['comment_author'],
258 $parent_comment->comment_author,
259 $post_type_label,
260 $post->post_title,
261 $comment_status
262 );
263 }
264 break;
265 case 'deleted_comment':
266 $text = sprintf(
267 /* translators: 1: Blog name, 2: Comment author, 3: Parent comment author, 4: Post type, 5: Post title, 6: Comment status */
268 esc_html__( '%1$s %2$s deleted comment ID %3$s, comment author: %4$s on %5$s "%6$s"', 'defender-security' ),
269 $blog_name,
270 $this->get_user_display( get_current_user_id() ),
271 $comment_id,
272 $comment['comment_author'],
273 $post_type_label,
274 $post->post_title
275 );
276 break;
277 case 'trash_comment':
278 $text = sprintf(
279 /* translators: 1: Blog name, 2: User's display name, 3: Comment ID, 4: Comment author, 5: Post type, 6: Post title */
280 esc_html__( '%1$s %2$s trashed comment ID %3$s, comment author: %4$s on %5$s "%6$s"', 'defender-security' ),
281 $blog_name,
282 $this->get_user_display( get_current_user_id() ),
283 $comment_id,
284 $comment['comment_author'],
285 $post_type_label,
286 $post->post_title
287 );
288 break;
289 case 'untrash_comment':
290 $text = sprintf(
291 /* translators: 1: Blog name, 2: User's display name, 3: Comment ID, 4: Comment author, 5: Post type, 6: Post title */
292 esc_html__( '%1$s %2$s untrashed comment ID %3$s, comment author: %4$s on %5$s "%6$s"', 'defender-security' ),
293 $blog_name,
294 $this->get_user_display( get_current_user_id() ),
295 $comment_id,
296 $comment['comment_author'],
297 $post_type_label,
298 $post->post_title
299 );
300 break;
301 case 'spam_comment':
302 $text = sprintf(
303 /* translators: 1: Blog name, 2: User's display name, 3: Comment ID, 4: Comment author, 5: Post type, 6: Post title */
304 esc_html__(
305 '%1$s %2$s marked comment ID %3$s, comment author: %4$s on %5$s "%6$s" as spam',
306 'defender-security'
307 ),
308 $blog_name,
309 $this->get_user_display( get_current_user_id() ),
310 $comment_id,
311 $comment['comment_author'],
312 $post_type_label,
313 $post->post_title
314 );
315 break;
316 case 'unspam_comment':
317 $text = sprintf(
318 /* translators: 1: Blog name, 2: User's display name, 3: Comment ID, 4: Comment author, 5: Post type, 6: Post title */
319 esc_html__(
320 '%1$s %2$s unmarked comment ID %3$s, comment author: %4$s on %5$s "%6$s" as spam',
321 'defender-security'
322 ),
323 $blog_name,
324 $this->get_user_display( get_current_user_id() ),
325 $comment_id,
326 $comment['comment_author'],
327 $post_type_label,
328 $post->post_title
329 );
330 break;
331 case 'edit_comment':
332 $text = sprintf(
333 /* translators: 1: Blog name, 2: User's display name, 3: Comment ID, 4: Comment author, 5: Post type, 6: Post title */
334 esc_html__( '%1$s %2$s edited comment ID %3$s, comment author: %4$s on %5$s "%6$s"', 'defender-security' ),
335 $blog_name,
336 $this->get_user_display( get_current_user_id() ),
337 $comment_id,
338 $comment['comment_author'],
339 $post_type_label,
340 $post->post_title
341 );
342 break;
343 default:
344 return false;
345 }
346
347 return array( $text, $post_type_label );
348 }
349 }
350