PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.0.3
Jetpack – WP Security, Backup, Speed, & Growth v12.0.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / widgets / simple-payments.php
jetpack / modules / widgets Last commit date
authors 8 years ago contact-info 5 years ago eu-cookie-law 4 years ago facebook-likebox 11 years ago flickr 4 years ago gallery 4 years ago goodreads 5 years ago google-translate 4 years ago image-widget 8 years ago instagram 6 years ago migrate-to-core 3 years ago milestone 3 years ago my-community 8 years ago simple-payments 4 years ago social-icons 4 years ago social-media-icons 5 years ago top-posts 8 years ago wordpress-post-widget 3 years ago authors.php 3 years ago blog-stats.php 3 years ago class-jetpack-eu-cookie-law-widget.php 3 years ago class-jetpack-instagram-widget.php 3 years ago contact-info.php 3 years ago customizer-controls.css 9 years ago customizer-utils.js 6 years ago facebook-likebox.php 3 years ago flickr.php 3 years ago gallery.php 3 years ago goodreads.php 3 years ago google-translate.php 3 years ago gravatar-profile.css 10 years ago gravatar-profile.php 3 years ago image-widget.php 3 years ago internet-defense-league.php 3 years ago mailchimp.php 3 years ago milestone.php 5 years ago my-community.php 3 years ago rsslinks-widget.php 3 years ago simple-payments.php 3 years ago social-icons.php 3 years ago social-media-icons.php 3 years ago top-posts.php 3 years ago twitter-timeline-admin.js 6 years ago twitter-timeline.php 3 years ago upcoming-events.php 3 years ago wordpress-post-widget.php 4 years ago
simple-payments.php
627 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move classes to appropriately-named class files.
4
5 use Automattic\Jetpack\Tracking;
6
7 /**
8 * Disable direct access/execution to/of the widget code.
9 */
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit;
12 }
13
14 if ( ! class_exists( 'Jetpack_Simple_Payments_Widget' ) ) {
15 /**
16 * Pay with PayPal (aka Simple Payments)
17 *
18 * Display a Pay with PayPal button as a Widget.
19 */
20 class Jetpack_Simple_Payments_Widget extends WP_Widget {
21 /**
22 * Currencies should be supported by PayPal:
23 *
24 * @var array $supported_currency_list
25 * @link https://developer.paypal.com/docs/api/reference/currency-codes/
26 *
27 * List has to be in sync with list at the block's client side and API's backend side:
28 * @link https://github.com/Automattic/jetpack/blob/31efa189ad223c0eb7ad085ac0650a23facf9ef5/extensions/blocks/simple-payments/constants.js#L9-L39
29 * @link https://github.com/Automattic/jetpack/blob/31efa189ad223c0eb7ad085ac0650a23facf9ef5/modules/simple-payments/simple-payments.php#L386-L415
30 *
31 * Indian Rupee (INR) is listed here for backwards compatibility with previously added widgets.
32 * It's not supported by Pay with PayPal because at the time of the creation of this file
33 * because it's limited to in-country PayPal India accounts only.
34 * Discussion: https://github.com/Automattic/wp-calypso/pull/28236
35 */
36 private static $supported_currency_list = array(
37 'USD' => '$',
38 'GBP' => '&#163;',
39 'JPY' => '&#165;',
40 'BRL' => 'R$',
41 'EUR' => '&#8364;',
42 'NZD' => 'NZ$',
43 'AUD' => 'A$',
44 'CAD' => 'C$',
45 'INR' => '',
46 'ILS' => '',
47 'RUB' => '',
48 'MXN' => 'MX$',
49 'SEK' => 'Skr',
50 'HUF' => 'Ft',
51 'CHF' => 'CHF',
52 'CZK' => '',
53 'DKK' => 'Dkr',
54 'HKD' => 'HK$',
55 'NOK' => 'Kr',
56 'PHP' => '',
57 'PLN' => 'PLN',
58 'SGD' => 'S$',
59 'TWD' => 'NT$',
60 'THB' => '฿',
61 );
62
63 /**
64 * Constructor.
65 */
66 public function __construct() {
67 parent::__construct(
68 'jetpack_simple_payments_widget',
69 /** This filter is documented in modules/widgets/facebook-likebox.php */
70 apply_filters( 'jetpack_widget_name', __( 'Pay with PayPal', 'jetpack' ) ),
71 array(
72 'classname' => 'jetpack-simple-payments',
73 'description' => __( 'Add a Pay with PayPal button as a Widget.', 'jetpack' ),
74 'customize_selective_refresh' => true,
75 )
76 );
77
78 global $pagenow;
79 if ( is_customize_preview() || 'widgets.php' === $pagenow ) {
80 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_styles' ) );
81 }
82
83 $jetpack_simple_payments = Jetpack_Simple_Payments::get_instance();
84 if ( is_customize_preview() && $jetpack_simple_payments->is_enabled_jetpack_simple_payments() ) {
85 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
86
87 add_filter( 'customize_refresh_nonces', array( $this, 'filter_nonces' ) );
88 add_action( 'wp_ajax_customize-jetpack-simple-payments-buttons-get', array( $this, 'ajax_get_payment_buttons' ) );
89 add_action( 'wp_ajax_customize-jetpack-simple-payments-button-save', array( $this, 'ajax_save_payment_button' ) );
90 add_action( 'wp_ajax_customize-jetpack-simple-payments-button-delete', array( $this, 'ajax_delete_payment_button' ) );
91 }
92
93 if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
94 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
95 }
96
97 add_filter( 'widget_types_to_hide_from_legacy_widget_block', array( $this, 'hide_simple_payment_widget' ) );
98 }
99
100 /**
101 * Return an array of the widgets hidden from the Legacy Widget block.
102 *
103 * This is used to hide the Pay with PayPal from the Legacy Widget block.
104 *
105 * @param array $widget_types the widget types that are currently hidden.
106 * @return array Widget types hidden from the Legacy Widget block
107 */
108 public function hide_simple_payment_widget( $widget_types ) {
109 $widget_types[] = 'jetpack_simple_payments_widget';
110 return $widget_types;
111 }
112
113 /**
114 * Return an associative array of default values.
115 *
116 * These values are used in new widgets.
117 *
118 * @return array Default values for the widget options.
119 */
120 private function defaults() {
121 $current_user = wp_get_current_user();
122 $default_product_id = $this->get_first_product_id();
123
124 return array(
125 'title' => '',
126 'product_post_id' => $default_product_id,
127 'form_action' => '',
128 'form_product_id' => 0,
129 'form_product_title' => '',
130 'form_product_description' => '',
131 'form_product_image_id' => 0,
132 'form_product_image_src' => '',
133 'form_product_currency' => '',
134 'form_product_price' => '',
135 'form_product_multiple' => '',
136 'form_product_email' => $current_user->user_email,
137 );
138 }
139
140 /**
141 * Adds a nonce for customizing menus.
142 *
143 * @param array $nonces Array of nonces.
144 * @return array $nonces Modified array of nonces.
145 */
146 public function filter_nonces( $nonces ) {
147 $nonces['customize-jetpack-simple-payments'] = wp_create_nonce( 'customize-jetpack-simple-payments' );
148 return $nonces;
149 }
150
151 /**
152 * Enqueue styles.
153 */
154 public function enqueue_style() {
155 wp_enqueue_style( 'jetpack-simple-payments-widget-style', plugins_url( 'simple-payments/style.css', __FILE__ ), array(), '20180518' );
156 }
157
158 /**
159 * Enqueue admin styles.
160 */
161 public function admin_enqueue_styles() {
162 wp_enqueue_style(
163 'jetpack-simple-payments-widget-customizer',
164 plugins_url( 'simple-payments/customizer.css', __FILE__ ),
165 array(),
166 JETPACK__VERSION
167 );
168 }
169
170 /**
171 * Enqueue admin scripts.
172 */
173 public function admin_enqueue_scripts() {
174 wp_enqueue_media();
175 wp_enqueue_script(
176 'jetpack-simple-payments-widget-customizer',
177 plugins_url( '/simple-payments/customizer.js', __FILE__ ),
178 array( 'jquery' ),
179 JETPACK__VERSION,
180 true
181 );
182 wp_localize_script(
183 'jetpack-simple-payments-widget-customizer',
184 'jpSimplePaymentsStrings',
185 array(
186 'deleteConfirmation' => __( 'Are you sure you want to delete this item? It will be disabled and removed from all locations where it currently appears.', 'jetpack' ),
187 )
188 );
189 }
190
191 /**
192 * Get payment buttons.
193 */
194 public function ajax_get_payment_buttons() {
195 if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
196 wp_send_json_error( 'bad_nonce', 400 );
197 }
198
199 if ( ! current_user_can( 'customize' ) ) {
200 wp_send_json_error( 'customize_not_allowed', 403 );
201 }
202
203 $post_type_object = get_post_type_object( Jetpack_Simple_Payments::$post_type_product );
204 if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
205 wp_send_json_error( 'insufficient_post_permissions', 403 );
206 }
207
208 $product_posts = get_posts(
209 array(
210 'numberposts' => 100,
211 'orderby' => 'date',
212 'post_type' => Jetpack_Simple_Payments::$post_type_product,
213 'post_status' => 'publish',
214 )
215 );
216
217 $formatted_products = array_map( array( $this, 'format_product_post_for_ajax_reponse' ), $product_posts );
218
219 wp_send_json_success( $formatted_products );
220 }
221
222 /**
223 * Format product_post object.
224 *
225 * @param object $product_post - info about the post the product is on.
226 */
227 public function format_product_post_for_ajax_reponse( $product_post ) {
228 return array(
229 'ID' => $product_post->ID,
230 'post_title' => $product_post->post_title,
231 );
232 }
233
234 /**
235 * Handle saving the simple payments widget.
236 */
237 public function ajax_save_payment_button() {
238 if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
239 wp_send_json_error( 'bad_nonce', 400 );
240 }
241
242 if ( ! current_user_can( 'customize' ) ) {
243 wp_send_json_error( 'customize_not_allowed', 403 );
244 }
245
246 $post_type_object = get_post_type_object( Jetpack_Simple_Payments::$post_type_product );
247 if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
248 wp_send_json_error( 'insufficient_post_permissions', 403 );
249 }
250
251 if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
252 wp_send_json_error( 'missing_params', 400 );
253 }
254
255 $params = wp_unslash( $_POST['params'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Manually validated by validate_ajax_params().
256 $errors = $this->validate_ajax_params( $params );
257 if ( ! empty( $errors->errors ) ) {
258 wp_send_json_error( $errors );
259 }
260
261 $product_post_id = isset( $params['product_post_id'] ) ? (int) $params['product_post_id'] : 0;
262
263 $product_post = array(
264 'ID' => $product_post_id,
265 'post_type' => Jetpack_Simple_Payments::$post_type_product,
266 'post_status' => 'publish',
267 'post_title' => $params['post_title'],
268 'post_content' => $params['post_content'],
269 '_thumbnail_id' => ! empty( $params['image_id'] ) ? $params['image_id'] : -1,
270 'meta_input' => array(
271 'spay_currency' => $params['currency'],
272 'spay_price' => $params['price'],
273 'spay_multiple' => isset( $params['multiple'] ) ? (int) $params['multiple'] : 0,
274 'spay_email' => is_email( $params['email'] ),
275 ),
276 );
277
278 if ( empty( $product_post_id ) ) {
279 $product_post_id = wp_insert_post( $product_post );
280 } else {
281 $product_post_id = wp_update_post( $product_post );
282 }
283
284 if ( ! $product_post_id || is_wp_error( $product_post_id ) ) {
285 wp_send_json_error( $product_post_id );
286 }
287
288 $tracks_properties = array(
289 'id' => $product_post_id,
290 'currency' => $params['currency'],
291 'price' => $params['price'],
292 );
293 if ( 0 === $product_post['ID'] ) {
294 $this->record_event( 'created', 'create', $tracks_properties );
295 } else {
296 $this->record_event( 'updated', 'update', $tracks_properties );
297 }
298
299 wp_send_json_success(
300 array(
301 'product_post_id' => $product_post_id,
302 'product_post_title' => $params['post_title'],
303 )
304 );
305 }
306
307 /**
308 * Handle deleting the simple payment widget.
309 */
310 public function ajax_delete_payment_button() {
311 if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
312 wp_send_json_error( 'bad_nonce', 400 );
313 }
314
315 if ( ! current_user_can( 'customize' ) ) {
316 wp_send_json_error( 'customize_not_allowed', 403 );
317 }
318
319 if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
320 wp_send_json_error( 'missing_params', 400 );
321 }
322
323 $params = wp_unslash( $_POST['params'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Manually validated just below.
324 $illegal_params = array_diff( array_keys( $params ), array( 'product_post_id' ) );
325 if ( ! empty( $illegal_params ) ) {
326 wp_send_json_error( 'illegal_params', 400 );
327 }
328
329 $product_id = (int) $params['product_post_id'];
330 $product_post = get_post( $product_id );
331
332 $return = array( 'status' => $product_post->post_status );
333
334 wp_delete_post( $product_id, true );
335 $status = get_post_status( $product_id );
336 if ( false === $status ) {
337 $return['status'] = 'deleted';
338 }
339
340 $this->record_event( 'deleted', 'delete', array( 'id' => $product_id ) );
341
342 wp_send_json_success( $return );
343 }
344
345 /**
346 * Returns the number of decimal places on string representing a price.
347 *
348 * @param string $number Price to check.
349 * @return number number of decimal places.
350 */
351 private function get_decimal_places( $number ) {
352 $parts = explode( '.', $number );
353 if ( count( $parts ) > 2 ) {
354 return null;
355 }
356
357 return isset( $parts[1] ) ? strlen( $parts[1] ) : 0;
358 }
359
360 /**
361 * Validate ajax parameters.
362 *
363 * @param array $params - the parameters.
364 */
365 public function validate_ajax_params( $params ) {
366 $errors = new WP_Error();
367
368 $illegal_params = array_diff( array_keys( $params ), array( 'product_post_id', 'post_title', 'post_content', 'image_id', 'currency', 'price', 'multiple', 'email' ) );
369 if ( ! empty( $illegal_params ) ) {
370 $errors->add( 'illegal_params', __( 'Invalid parameters.', 'jetpack' ) );
371 }
372
373 if ( empty( $params['post_title'] ) ) {
374 $errors->add( 'post_title', __( "People need to know what they're paying for! Please add a brief title.", 'jetpack' ) );
375 }
376
377 if ( empty( $params['price'] ) || ! is_numeric( $params['price'] ) || (float) $params['price'] <= 0 ) {
378 $errors->add( 'price', __( 'Everything comes with a price tag these days. Please add a your product price.', 'jetpack' ) );
379 }
380
381 // Japan's Yen is the only supported currency with a zero decimal precision.
382 $precision = strtoupper( $params['currency'] ) === 'JPY' ? 0 : 2;
383 $price_decimal_places = $this->get_decimal_places( $params['price'] );
384 if ( $price_decimal_places === null || $price_decimal_places > $precision ) {
385 $errors->add( 'price', __( 'Invalid price', 'jetpack' ) );
386 }
387
388 if ( empty( $params['email'] ) || ! is_email( $params['email'] ) ) {
389 $errors->add( 'email', __( 'We want to make sure payments reach you, so please add an email address.', 'jetpack' ) );
390 }
391
392 return $errors;
393 }
394
395 /**
396 * Get the id of the first product.
397 */
398 public function get_first_product_id() {
399 $product_posts = get_posts(
400 array(
401 'numberposts' => 1,
402 'orderby' => 'date',
403 'post_type' => Jetpack_Simple_Payments::$post_type_product,
404 'post_status' => 'publish',
405 )
406 );
407
408 return ! empty( $product_posts ) ? $product_posts[0]->ID : null;
409 }
410
411 /**
412 * Front-end display of widget.
413 *
414 * @see WP_Widget::widget()
415 *
416 * @param array $args Widget arguments.
417 * @param array $instance Saved values from database.
418 */
419 public function widget( $args, $instance ) {
420 $instance = wp_parse_args( $instance, $this->defaults() );
421
422 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
423
424 /** This filter is documented in core/src/wp-includes/default-widgets.php */
425 $title = apply_filters( 'widget_title', $instance['title'] );
426 if ( ! empty( $title ) ) {
427 echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
428 }
429
430 echo '<div class="jetpack-simple-payments-content">';
431
432 if ( ! empty( $instance['form_action'] ) && in_array( $instance['form_action'], array( 'add', 'edit' ), true ) && is_customize_preview() ) {
433 require __DIR__ . '/simple-payments/widget.php';
434 } else {
435 $jsp = Jetpack_Simple_Payments::get_instance();
436 $simple_payments_button = $jsp->parse_shortcode(
437 array(
438 'id' => $instance['product_post_id'],
439 )
440 );
441
442 if ( $simple_payments_button !== null || is_customize_preview() ) {
443 echo $simple_payments_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
444 }
445 }
446
447 echo '</div><!--simple-payments-->';
448
449 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
450
451 /** This action is already documented in modules/widgets/gravatar-profile.php */
452 do_action( 'jetpack_stats_extra', 'widget_view', 'simple_payments' );
453 }
454
455 /**
456 * Gets the latests field value from either the old instance or the new instance.
457 *
458 * @param array $new_instance mixed Array of values for the new form instance.
459 * @param array $old_instance mixed Array of values for the old form instance.
460 * @param mixed $field mixed Field value.
461 */
462 private function get_latest_field_value( $new_instance, $old_instance, $field ) {
463 return ! empty( $new_instance[ $field ] )
464 ? sanitize_text_field( $new_instance[ $field ] )
465 : $old_instance[ $field ];
466 }
467
468 /**
469 * Gets the product fields from the product post. If no post found
470 * it returns the default values.
471 *
472 * @param int $product_post_id Product Post ID.
473 * @return array $fields Product Fields from the Product Post.
474 */
475 private function get_product_from_post( $product_post_id ) {
476 $product_post = get_post( $product_post_id );
477 $form_product_id = $product_post_id;
478 if ( ! empty( $product_post ) ) {
479 $form_product_image_id = get_post_thumbnail_id( $product_post_id );
480
481 return array(
482 'form_product_id' => $form_product_id,
483 'form_product_title' => get_the_title( $product_post ),
484 'form_product_description' => $product_post->post_content,
485 'form_product_image_id' => $form_product_image_id,
486 'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
487 'form_product_currency' => get_post_meta( $product_post_id, 'spay_currency', true ),
488 'form_product_price' => get_post_meta( $product_post_id, 'spay_price', true ),
489 'form_product_multiple' => get_post_meta( $product_post_id, 'spay_multiple', true ) || '0',
490 'form_product_email' => get_post_meta( $product_post_id, 'spay_email', true ),
491 );
492 }
493
494 return $this->defaults();
495 }
496
497 /**
498 * Record a Track event and bump a MC stat.
499 *
500 * @param string $stat_name - the name of the stat.
501 * @param string $event_action - the action we're recording.
502 * @param array $event_properties - proprties of the event.
503 */
504 private function record_event( $stat_name, $event_action, $event_properties = array() ) {
505 $current_user = wp_get_current_user();
506
507 // `bumps_stats_extra` only exists on .com
508 if ( function_exists( 'bump_stats_extras' ) ) {
509 require_lib( 'tracks/client' );
510 tracks_record_event( $current_user, 'simple_payments_button_' . $event_action, $event_properties );
511 /** This action is documented in modules/widgets/social-media-icons.php */
512 do_action( 'jetpack_bump_stats_extra', 'jetpack-simple_payments', $stat_name );
513 return;
514 }
515
516 $tracking = new Tracking();
517 $tracking->tracks_record_event( $current_user, 'jetpack_wpa_simple_payments_button_' . $event_action, $event_properties );
518 $jetpack = Jetpack::init();
519 // $jetpack->stat automatically prepends the stat group with 'jetpack-'
520 $jetpack->stat( 'simple_payments', $stat_name );
521 $jetpack->do_stats( 'server_side' );
522 }
523
524 /**
525 * Sanitize widget form values as they are saved.
526 *
527 * @see WP_Widget::update()
528 *
529 * @param array $new_instance Values just sent to be saved.
530 * @param array $old_instance Previously saved values from database.
531 *
532 * @return array Updated safe values to be saved.
533 */
534 public function update( $new_instance, $old_instance ) {
535 $defaults = $this->defaults();
536 // do not overrite `product_post_id` for `$new_instance` with the defaults.
537 $new_instance = wp_parse_args( $new_instance, array_diff_key( $defaults, array( 'product_post_id' => 0 ) ) );
538 $old_instance = wp_parse_args( $old_instance, $defaults );
539
540 $required_widget_props = array(
541 'title' => $this->get_latest_field_value( $new_instance, $old_instance, 'title' ),
542 'product_post_id' => $this->get_latest_field_value( $new_instance, $old_instance, 'product_post_id' ),
543 'form_action' => $this->get_latest_field_value( $new_instance, $old_instance, 'form_action' ),
544 );
545
546 if ( strcmp( $new_instance['form_action'], $old_instance['form_action'] ) !== 0 ) {
547 if ( 'edit' === $new_instance['form_action'] ) {
548 return array_merge( $this->get_product_from_post( (int) $old_instance['product_post_id'] ), $required_widget_props );
549 }
550
551 if ( 'clear' === $new_instance['form_action'] ) {
552 return array_merge( $this->defaults(), $required_widget_props );
553 }
554 }
555
556 $form_product_image_id = (int) $new_instance['form_product_image_id'];
557
558 $form_product_email = ! empty( $new_instance['form_product_email'] )
559 ? sanitize_text_field( $new_instance['form_product_email'] )
560 : $defaults['form_product_email'];
561
562 return array_merge(
563 $required_widget_props,
564 array(
565 'form_product_id' => (int) $new_instance['form_product_id'],
566 'form_product_title' => sanitize_text_field( $new_instance['form_product_title'] ),
567 'form_product_description' => sanitize_text_field( $new_instance['form_product_description'] ),
568 'form_product_image_id' => $form_product_image_id,
569 'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
570 'form_product_currency' => sanitize_text_field( $new_instance['form_product_currency'] ),
571 'form_product_price' => sanitize_text_field( $new_instance['form_product_price'] ),
572 'form_product_multiple' => sanitize_text_field( $new_instance['form_product_multiple'] ),
573 'form_product_email' => $form_product_email,
574 )
575 );
576 }
577
578 /**
579 * Back-end widget form.
580 *
581 * @see WP_Widget::form()
582 *
583 * @param array $instance Previously saved values from database.
584 */
585 public function form( $instance ) {
586 $jetpack_simple_payments = Jetpack_Simple_Payments::get_instance();
587 if ( ! method_exists( $jetpack_simple_payments, 'is_enabled_jetpack_simple_payments' ) ) {
588 return;
589 }
590 if ( ! $jetpack_simple_payments->is_enabled_jetpack_simple_payments() ) {
591 require __DIR__ . '/simple-payments/admin-warning.php';
592 return;
593 }
594
595 $instance = wp_parse_args( $instance, $this->defaults() );
596
597 $product_posts = get_posts( // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
598 array(
599 'numberposts' => 100,
600 'orderby' => 'date',
601 'post_type' => Jetpack_Simple_Payments::$post_type_product,
602 'post_status' => 'publish',
603 )
604 );
605
606 require __DIR__ . '/simple-payments/form.php';
607 }
608 }
609
610 /**
611 * Register Jetpack_Simple_Payments_Widget widget.
612 */
613 function register_widget_jetpack_simple_payments() {
614 if ( ! class_exists( 'Jetpack_Simple_Payments' ) ) {
615 return;
616 }
617
618 $jetpack_simple_payments = Jetpack_Simple_Payments::get_instance();
619 if ( ! $jetpack_simple_payments->is_enabled_jetpack_simple_payments() ) {
620 return;
621 }
622
623 register_widget( 'Jetpack_Simple_Payments_Widget' );
624 }
625 add_action( 'widgets_init', 'register_widget_jetpack_simple_payments' );
626 }
627