Passed
Pull Request — dev/2.5.0 (#307)
by
unknown
07:19 queued 04:01
created

EmailLogger   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 205
Duplicated Lines 0 %

Test Coverage

Coverage 33.33%

Importance

Changes 15
Bugs 0 Features 0
Metric Value
eloc 60
dl 0
loc 205
ccs 20
cts 60
cp 0.3333
rs 10
c 15
b 0
f 0
wmc 14

6 Methods

Rating   Name   Duplication   Size   Complexity  
A load() 0 14 1
A mark_email_log_as_failed() 0 18 4
A log_buddy_press_email() 0 20 4
A log_email() 0 82 2
A wp_mail_filter() 0 3 1
A on_email_failed() 0 10 2
1
<?php namespace EmailLog\Core;
2
3
/**
4
 * Log's emails sent through `wp_mail`.
5
 *
6
 * @package EmailLog\Core
7
 * @since   2.0
8
 */
9
class EmailLogger implements Loadie {
10
11
	/**
12
	 * Load the logger.
13
	 */
14
	public function load() {
15
		add_filter( 'wp_mail', array( $this, 'wp_mail_filter' ) );
16
		add_action( 'wp_mail_failed', array( $this, 'on_email_failed' ) );
17
18
		/**
19
		 * These actions are required for logging BuddyPress emails, since BuddyPress does
20
		 * not use wp_mail for sending emails.
21
		 *
22
		 * Support for BuddyPress was added in v2.3.2
23
		 *
24
		 * @link https://github.com/sudar/email-log/issues/249
25
		 */
26
		add_action( 'bp_send_email_success', array( $this, 'log_buddy_press_email' ), 10, 2 );
27
		add_action( 'bp_send_email_failure', array( $this, 'log_buddy_press_email' ), 10, 2 );
28
	}
29
30
	/**
31
	 * wp_mail filter that logs email to database.
32
	 *
33
	 * @param array $original_mail_info Information about email.
34
	 *
35
	 * @return array Information about email.
36
	 */
37
	public function wp_mail_filter( $original_mail_info ) {
38
		$this->log_email( $original_mail_info );
39
		return $original_mail_info;
40
	}
41
42
	/**
43
	 * Logs email to database.
44
	 *
45
	 * @param array $original_mail_info Information about email.
46
	 *
47
	 * @return boolean|int Insertion failure/success.
48
	 */
49 1
	public function log_email( $original_mail_info ) {
50
		/**
51
		 * Hook to modify wp_mail contents before Email Log plugin logs.
52
		 *
53
		 * @param array $original_mail_info {
54
		 *     @type string|array $to
55
		 *     @type string       $subject
56
		 *     @type string       $message
57
		 *     @type string|array $headers
58
		 *     @type string|array $attachment
59
		 * }
60
		 *
61
		 * @since 2.0.0
62
		 */
63 1
		$original_mail_info = apply_filters( 'el_wp_mail_log', $original_mail_info );
64
65
		// Sometimes the array passed to the `wp_mail` filter may not contain all the required keys.
66
		// See https://wordpress.org/support/topic/illegal-string-offset-attachments/.
67 1
		$mail_info = wp_parse_args(
68 1
			$original_mail_info,
69
			array(
70 1
				'to'          => '',
71
				'subject'     => '',
72
				'message'     => '',
73
				'headers'     => '',
74
				'attachments' => array(),
75
			)
76
		);
77
78
		$log = array(
79 1
			'to_email'        => \EmailLog\Util\stringify( $mail_info['to'] ),
80 1
			'subject'         => $mail_info['subject'],
81 1
			'message'         => $mail_info['message'],
82 1
			'headers'         => \EmailLog\Util\stringify( $mail_info['headers'], "\n" ),
83 1
			'attachment_name' => \EmailLog\Util\stringify( $mail_info['attachments'] ),
84 1
			'sent_date'       => current_time( 'mysql' ),
85 1
			'ip_address'      => $_SERVER['REMOTE_ADDR'],
86 1
			'result'          => 1,
87
		);
88
89 1
		if ( empty( $log['attachment_name'] ) ) {
90 1
			$log['attachments'] = 'false';
91
		} else {
92
			$log['attachments'] = 'true';
93
		}
94
95
		/**
96
		 * Filters the mail info right before inserting on the table.
97
		 *
98
		 * Masked fields would use this filter to avoid modifying the original data sent to
99
		 * `wp_mail() function`
100
		 *
101
		 * @param array $log                Email Log that is about to be inserted into db.
102
		 * @param array $original_mail_info Original mail info that was passed to `wp_mail` filter.
103
		 *
104
		 * @since 2.3.2
105
		 */
106 1
		$log = apply_filters( 'el_email_log_before_insert', $log, $original_mail_info );
107
108 1
		$email_log = email_log();
109 1
		$result    = $email_log->table_manager->insert_log( $log );
110
111
		/**
112
		 * Fires the `el_email_log_inserted` action right after the log is inserted in to DB.
113
		 *
114
		 * @since 2.3.0
115
		 *
116
		 * @param array $log {
117
		 *      @type string $to
118
		 *      @type string $subject
119
		 *      @type string $message
120
		 *      @type string $headers
121
		 *      @type string $attachments
122
		 *      @type string $attachment_name
123
		 *      @type string $sent_date
124
		 *      @type string $ip_address
125
		 *      @type bool   $result
126
		 * }
127
		 */
128 1
		do_action( 'el_email_log_inserted', $log );
129
130 1
		return $result;
131
	}
132
133
	/**
134
	 * Updates the failed email in the DB.
135
	 *
136
	 * @param \WP_Error $wp_error The error instance.
137
	 *
138
	 * @since 2.4.0 Use is_wp_error() to validate the type of $wp_error.
139
	 * @since 2.3.0
140
	 *
141
	 * @see   is_wp_error()
142
	 * @see   email_log()
143
	 */
144
	public function on_email_failed( $wp_error ) {
145
		if ( ! is_wp_error( $wp_error ) ) {
146
			return;
147
		}
148
149
		// @see wp-includes/pluggable.php#500
150
		$mail_error_data = $wp_error->get_error_data( 'wp_mail_failed' );
151
		$mail_error_message = $wp_error->get_error_message( 'wp_mail_failed' );
152
153
		$this->mark_email_log_as_failed( $mail_error_data, $mail_error_message );
154
	}
155
156
	/**
157
	 * Prepare BuddyPress emails to log into database.
158
	 *
159
	 * @since 2.3.2
160
	 *
161
	 * @param bool      $status  Mail sent status.
162
	 * @param \BP_Email $bp_mail Information about email.
163
	 */
164
	public function log_buddy_press_email( $status, $bp_mail ) {
165
		if ( ! class_exists( '\\BP_Email' ) ) {
166
			return;
167
		}
168
169
		if ( $bp_mail instanceof \BP_Email ) {
0 ignored issues
show
Bug introduced by
The type BP_Email was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
170
			return;
171
		}
172
173
		$log = array(
174
			'to'      => array_shift( $bp_mail->get_to() )->get_address(),
0 ignored issues
show
Bug introduced by
$bp_mail->get_to() cannot be passed to array_shift() as the parameter $array expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

174
			'to'      => array_shift( /** @scrutinizer ignore-type */ $bp_mail->get_to() )->get_address(),
Loading history...
175
			'subject' => $bp_mail->get_subject( 'replace-tokens' ),
176
			'message' => $bp_mail->get_content( 'replace-tokens' ),
177
			'headers' => $bp_mail->get_headers( 'replace-tokens ' ),
178
		);
179
180
		$this->log_email( $log );
181
182
		if ( ! $status ) {
183
			$this->mark_email_log_as_failed( $log );
184
		}
185
	}
186
187
	/**
188
	 * Mark email log as failed.
189
	 *
190
	 * @param array  $log           Email Log.
191
	 * @param string $error_message Error message.
192
	 *
193
	 * @since 2.3.2
194
	 * @since 2.4.0 Store the error message.
195
	 */
196
	protected function mark_email_log_as_failed( $log, $error_message = '' ) {
197
		if ( ! is_array( $log ) ) {
0 ignored issues
show
introduced by
The condition is_array($log) is always true.
Loading history...
198
			return;
199
		}
200
201
		if ( ! isset( $log['to'], $log['subject'] ) ) {
202
			return;
203
		}
204
205
		$email_log = email_log();
206
207
		$log_item_id = $email_log->table_manager->fetch_log_id_by_data( $log );
208
209
		if ( empty( $log_item_id ) ) {
210
			return;
211
		}
212
213
		$email_log->table_manager->mark_log_as_failed( $log_item_id, $error_message );
214
	}
215
}
216