Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
5.45% covered (danger)
5.45%
3 / 55
10.00% covered (danger)
10.00%
1 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
WooCommerce
5.45% covered (danger)
5.45%
3 / 55
10.00% covered (danger)
10.00%
1 / 10
470.07
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_description
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 init
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 handle_ses_bounce
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 handle_ses_complaint
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setup_test
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 verify_test
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 delete_test_data
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 display_bounce_notification
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * Functionality for WooCommerce to highlight in orders when the user's email address is incorrect.
4 *
5 * @see https://wordpress.org/plugins/woocommerce
6 *
7 * @link       https://BrianHenry.ie
8 * @since      1.1.0
9 *
10 * @package brianhenryie/bh-wp-aws-ses-bounce-handler
11 */
12
13namespace BrianHenryIE\AWS_SES_Bounce_Handler\API\Integrations;
14
15use BrianHenryIE\AWS_SES_Bounce_Handler\Admin\Bounce_Handler_Test;
16
17use BrianHenryIE\AWS_SES_Bounce_Handler\API\SES_Bounce_Handler_Integration_Interface;
18use Psr\Log\LoggerAwareTrait;
19use Psr\Log\LoggerInterface;
20use stdClass;
21use WC_Order;
22
23/**
24 * Hook onto `handle_ses_bounce` to add order note and meta key, hook onto `admin_notices` to display notice on orders.
25 */
26class WooCommerce implements SES_Bounce_Handler_Integration_Interface {
27
28    use LoggerAwareTrait;
29
30    public function __construct( LoggerInterface $logger ) {
31        $this->setLogger( $logger );
32    }
33
34    const BOUNCED_META_KEY = 'bh_wp_aws_ses_bounce_hander_bounced';
35
36    /**
37     * Return a description for the admin UI, explaining a note and notice will be added to orders.
38     *
39     * @return string
40     */
41    public function get_description(): string {
42        return 'Adds a note and notice on orders whose email address bounced';
43    }
44
45    /**
46     * Add the hook for displaying the order notice.
47     */
48    public function init(): void {
49        add_action( 'admin_notices', array( $this, 'display_bounce_notification' ) );
50    }
51
52    /**
53     * Check is WooCommerce installed.
54     *
55     * @return bool
56     */
57    public function is_enabled(): bool {
58        return class_exists( \WooCommerce::class );
59    }
60
61    /**
62     * Add a note to orders whose email addresses are invalid.
63     *
64     * @hooked handle_ses_bounce
65     *
66     * @param string   $email_address     The email address that has bounced.
67     * @param stdClass $bounced_recipient Parent object with emailAddress, status, action, diagnosticCode.
68     * @param stdClass $message           Parent object of complete notification.
69     */
70    public function handle_ses_bounce( string $email_address, stdClass $bounced_recipient, stdClass $message ): void {
71
72        if ( ! $this->is_enabled() ) {
73            return;
74        }
75
76        /**
77         * Find any orders made with this email address.
78         *
79         * @var WC_Order[] $customer_orders
80         */
81        $customer_orders = wc_get_orders( array( 'customer' => $email_address ) );
82
83        foreach ( $customer_orders as $order ) {
84
85            $order->add_order_note( 'Email address bounced' );
86
87            $order->add_meta_data( self::BOUNCED_META_KEY, $email_address, true );
88
89            $order->save();
90        }
91    }
92
93    /**
94     * Do nothing.
95     *
96     * @hooked handle_ses_complaint
97     *
98     * @param string   $email_address The email address which complained about our email.
99     * @param stdClass $complained_recipient The SES notification the email address was received in.
100     * @param stdClass $message The SNS notification the SES notification was received in.
101     */
102    public function handle_ses_complaint( string $email_address, stdClass $complained_recipient, stdClass $message ): void {}
103
104    /**
105     * Create an order with the bounce simulator email address.
106     *
107     * @param Bounce_Handler_Test $test The test orchestrator and configuration.
108     *
109     * @return ?array<string, array<string,mixed>|string>
110     */
111    public function setup_test( Bounce_Handler_Test $test ): ?array {
112
113        if ( ! $this->is_enabled() ) {
114            return null;
115        }
116
117        $order = wc_create_order();
118
119        if ( ! ( $order instanceof WC_Order ) ) {
120            // TODO.
121            return null;
122        }
123
124        $address = array(
125            'email' => $test->get_email(),
126        );
127        $order->set_address( $address, 'billing' );
128        $order_bounced_meta_value = $order->get_meta( self::BOUNCED_META_KEY );
129        $order_bounced_meta_value = empty( $order_bounced_meta_value ) ? 'empty' : $order_bounced_meta_value;
130
131        $order_url = admin_url( 'post.php?post=' . $order->get_id() . '&action=edit' );
132
133        $data['wc_order_id']                 = $order->get_id();
134        $data['wc_order_bounced_meta_value'] = $order_bounced_meta_value;
135
136        $html = '<p>WooCommerce <a href="' . $order_url . '">order ' . $order->get_id() . '</a> created with meta key <em>' . self::BOUNCED_META_KEY . '</em> value: <em>' . $order_bounced_meta_value . '</em></p>';
137
138        return array(
139            'data' => $data,
140            'html' => $html,
141        );
142    }
143
144    /**
145     * Verify the order has metadata added.
146     *
147     * @param array $test_data {int: wc_order_id}.
148     *
149     * @return array
150     */
151    public function verify_test( array $test_data ): ?array {
152
153        $order = wc_get_order( intval( $test_data['wc_order_id'] ) );
154
155        if ( ! $order instanceof \WC_Order ) {
156
157            return array(
158                'success' => false,
159                'html'    => '<p>WooCommerce order not found</p>',
160            );
161        }
162
163        $order_bounced_meta_value = $order->get_meta( self::BOUNCED_META_KEY );
164
165        if ( empty( $order_bounced_meta_value ) ) {
166
167            return array(
168                'success' => false,
169                'html'    => '<p>WooCommerce order meta key not found</p>',
170            );
171        }
172
173        $success = true;
174
175        $order_url = admin_url( 'post.php?post=' . $order->get_id() . '&action=edit' );
176
177        $html = '<p>WooCommerce <a href="' . $order_url . '">order ' . $order->get_id() . '</a> found with meta key <em>' . self::BOUNCED_META_KEY . '</em> value: <em>' . $order_bounced_meta_value . '</em></p>';
178
179        return array(
180            'success' => $success,
181            'html'    => $html,
182        );
183
184    }
185
186    /**
187     * Delete the order created for the test.
188     *
189     * @param array{'wc_order_id': int} $test_data The data created and saved during setup_test().
190     */
191    public function delete_test_data( array $test_data ): bool {
192
193        if ( isset( $test_data['wc_order_id'] ) && class_exists( \WooCommerce::class ) ) {
194            wp_delete_post( intval( $test_data['wc_order_id'] ) );
195        }
196
197        return true;
198    }
199
200    /**
201     * Display an admin notice if this order's customer email has bounced.
202     *
203     * @hooked admin_notices
204     *
205     * @see https://stackoverflow.com/questions/56971501/how-to-add-admin-notices-on-woocommerce-order-edit-page
206     */
207    public function display_bounce_notification(): void {
208
209        if ( ! $this->is_enabled() ) {
210            return;
211        }
212
213        $id = get_the_ID();
214
215        if ( false === $id ) {
216            return;
217        }
218
219        $order = wc_get_order( $id );
220
221        if ( ! $order instanceof WC_Order ) {
222            return;
223        }
224
225        $bounced_email = $order->get_meta( self::BOUNCED_META_KEY );
226
227        if ( ! empty( $bounced_email ) ) {
228
229            $notice = sprintf(
230                "<div class='notice notice-warning'><p>%s <em>%s</em> %s.</p></div>",
231                __( "The customer's email address", 'bh-wp-aws-ses-bounce-handler' ),
232                $bounced_email,
233                __( 'is invalid', 'bh-wp-aws-ses-bounce-handler' )
234            );
235
236            $allowed_html = array(
237                'div' => array(
238                    'class' => array(),
239                ),
240                'p'   => array(),
241                'em'  => array(),
242            );
243
244            echo wp_kses( $notice, $allowed_html );
245        }
246    }
247
248}