Completed
Push — 19-feature/export-logs-in-batc... ( a346a8...47f618 )
by Sudar
15:28 queued 09:06
created

EmailLogger::on_email_failed()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 10
ccs 0
cts 6
cp 0
crap 6
rs 10
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, 'log_email' ) );
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
	 * Logs email to database.
32
	 *
33
	 * @param array $original_mail_info Information about email.
34
	 *
35
	 * @return array Information about email.
36
	 */
37 1
	public function log_email( $original_mail_info ) {
38
		/**
39
		 * Hook to modify wp_mail contents before Email Log plugin logs.
40
		 *
41
		 * @param array $original_mail_info {
42
		 *     @type string|array $to
43
		 *     @type string       $subject
44
		 *     @type string       $message
45
		 *     @type string|array $headers
46
		 *     @type string|array $attachment
47
		 * }
48
		 *
49
		 * @since 2.0.0
50
		 */
51 1
		$original_mail_info = apply_filters( 'el_wp_mail_log', $original_mail_info );
52
53
		// Sometimes the array passed to the `wp_mail` filter may not contain all the required keys.
54
		// See https://wordpress.org/support/topic/illegal-string-offset-attachments/.
55 1
		$mail_info = wp_parse_args(
56 1
			$original_mail_info,
57
			array(
58 1
				'to'          => '',
59
				'subject'     => '',
60
				'message'     => '',
61
				'headers'     => '',
62
				'attachments' => array(),
63
			)
64
		);
65
66
		$log = array(
67 1
			'to_email'        => \EmailLog\Util\stringify( $mail_info['to'] ),
68 1
			'subject'         => $mail_info['subject'],
69 1
			'message'         => $mail_info['message'],
70 1
			'headers'         => \EmailLog\Util\stringify( $mail_info['headers'], "\n" ),
71 1
			'attachment_name' => \EmailLog\Util\stringify( $mail_info['attachments'] ),
72 1
			'sent_date'       => current_time( 'mysql' ),
73 1
			'ip_address'      => $_SERVER['REMOTE_ADDR'],
74 1
			'result'          => 1,
75
		);
76
77 1
		if ( empty( $log['attachment_name'] ) ) {
78 1
			$log['attachments'] = 'false';
79
		} else {
80
			$log['attachments'] = 'true';
81
		}
82
83
		/**
84
		 * Filters the mail info right before inserting on the table.
85
		 *
86
		 * Masked fields would use this filter to avoid modifying the original data sent to
87
		 * `wp_mail() function`
88
		 *
89
		 * @param array $log                Email Log that is about to be inserted into db.
90
		 * @param array $original_mail_info Original mail info that was passed to `wp_mail` filter.
91
		 *
92
		 * @since 2.3.2
93
		 */
94 1
		$log = apply_filters( 'el_email_log_before_insert', $log, $original_mail_info );
95
96 1
		$email_log = email_log();
97 1
		$email_log->table_manager->insert_log( $log );
98
99
		/**
100
		 * Fires the `el_email_log_inserted` action right after the log is inserted in to DB.
101
		 *
102
		 * @since 2.3.0
103
		 *
104
		 * @param array $log {
105
		 *      @type string $to
106
		 *      @type string $subject
107
		 *      @type string $message
108
		 *      @type string $headers
109
		 *      @type string $attachments
110
		 *      @type string $attachment_name
111
		 *      @type string $sent_date
112
		 *      @type string $ip_address
113
		 *      @type bool   $result
114
		 * }
115
		 */
116 1
		do_action( 'el_email_log_inserted', $log );
117
118 1
		return $original_mail_info;
119
	}
120
121
	/**
122
	 * Updates the failed email in the DB.
123
	 *
124
	 * @param \WP_Error $wp_error The error instance.
125
	 *
126
	 * @since 2.4.0 Use is_wp_error() to validate the type of $wp_error.
127
	 * @since 2.3.0
128
	 *
129
	 * @see   is_wp_error()
130
	 * @see   email_log()
131
	 */
132
	public function on_email_failed( $wp_error ) {
133
		if ( ! is_wp_error( $wp_error ) ) {
134
			return;
135
		}
136
137
		// @see wp-includes/pluggable.php#500
138
		$mail_error_data = $wp_error->get_error_data( 'wp_mail_failed' );
139
		$mail_error_message = $wp_error->get_error_message( 'wp_mail_failed' );
140
141
		$this->mark_email_log_as_failed( $mail_error_data, $mail_error_message );
142
	}
143
144
	/**
145
	 * Prepare BuddyPress emails to log into database.
146
	 *
147
	 * @since 2.3.2
148
	 *
149
	 * @param bool      $status  Mail sent status.
150
	 * @param \BP_Email $bp_mail Information about email.
151
	 */
152
	public function log_buddy_press_email( $status, $bp_mail ) {
153
		if ( ! class_exists( '\\BP_Email' ) ) {
154
			return;
155
		}
156
157
		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...
158
			return;
159
		}
160
161
		$log = array(
162
			'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

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