Completed
Push — add/simple-payments-widget-pro... ( 6fa3f4 )
by
unknown
09:54
created

Jetpack_Simple_Payments_Widget::update()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 38
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 26
nc 6
nop 2
dl 0
loc 38
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * Disable direct access/execution to/of the widget code.
4
 */
5
if ( ! defined( 'ABSPATH' ) ) {
6
	exit;
7
}
8
9
if ( ! class_exists( 'Jetpack_Simple_Payments_Widget' ) ) {
10
	/**
11
	 * Simple Payments Button
12
	 *
13
	 * Display a Simple Payment Button as a Widget.
14
	 */
15
	class Jetpack_Simple_Payments_Widget extends WP_Widget {
16
		// https://developer.paypal.com/docs/integration/direct/rest/currency-codes/
17
		private static $supported_currency_list = array(
0 ignored issues
show
Unused Code introduced by
The property $supported_currency_list is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
18
			'USD' => '$',
19
			'GBP' => '&#163;',
20
			'JPY' => '&#165;',
21
			'BRL' => 'R$',
22
			'EUR' => '&#8364;',
23
			'NZD' => 'NZ$',
24
			'AUD' => 'A$',
25
			'CAD' => 'C$',
26
			'INR' => '₹',
27
			'ILS' => '₪',
28
			'RUB' => '₽',
29
			'MXN' => 'MX$',
30
			'SEK' => 'Skr',
31
			'HUF' => 'Ft',
32
			'CHF' => 'CHF',
33
			'CZK' => 'Kč',
34
			'DKK' => 'Dkr',
35
			'HKD' => 'HK$',
36
			'NOK' => 'Kr',
37
			'PHP' => '₱',
38
			'PLN' => 'PLN',
39
			'SGD' => 'S$',
40
			'TWD' => 'NT$',
41
			'THB' => '฿',
42
		);
43
44
		/**
45
		 * Constructor.
46
		 */
47
		function __construct() {
48
			parent::__construct(
49
				'jetpack_simple_payments_widget',
50
				/** This filter is documented in modules/widgets/facebook-likebox.php */
51
				apply_filters( 'jetpack_widget_name', __( 'Simple Payments', 'jetpack' ) ),
52
				array(
53
					'classname' => 'jetpack-simple-payments',
54
					'description' => __( 'Add a Simple Payment Button as a Widget.', 'jetpack' ),
55
					'customize_selective_refresh' => true,
56
				)
57
			);
58
59
			if ( is_customize_preview() ) {
60
				add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_styles_and_scripts' ) );
61
62
				add_filter( 'customize_refresh_nonces', array( $this, 'filter_nonces' ) );
63
				add_action( 'wp_ajax_customize-jetpack-simple-payments-buttons-get', array( $this, 'ajax_get_payment_buttons' ) );
64
				add_action( 'wp_ajax_customize-jetpack-simple-payments-button-save', array( $this, 'ajax_save_payment_button' ) );
65
				add_action( 'wp_ajax_customize-jetpack-simple-payments-button-delete', array( $this, 'ajax_delete_payment_button' ) );
66
			}
67
68
			if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
69
				add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
70
			}
71
		}
72
73
		/**
74
		 * Return an associative array of default values.
75
		 *
76
		 * These values are used in new widgets.
77
		 *
78
		 * @return array Default values for the widget options.
79
		 */
80
		private function defaults() {
81
			$current_user = wp_get_current_user();
82
83
			return array(
84
				'title' => '',
85
				'product_post_id' => 0,
86
				'form_action' => '',
87
				'form_product_id' => 0,
88
				'form_product_title' => '',
89
				'form_product_description' => '',
90
				'form_product_image_id' => 0,
91
				'form_product_image_src' => '',
92
				'form_product_currency' => '',
93
				'form_product_price' => '',
94
				'form_product_multiple' => '',
95
				'form_product_email' => $current_user->user_email,
96
			);
97
		}
98
99
		/**
100
		 * Adds a nonce for customizing menus.
101
		 *
102
		 * @param array $nonces Array of nonces.
103
		 * @return array $nonces Modified array of nonces.
104
		 */
105
		function filter_nonces( $nonces ) {
106
			$nonces['customize-jetpack-simple-payments'] = wp_create_nonce( 'customize-jetpack-simple-payments' );
107
			return $nonces;
108
		}
109
110
		function enqueue_style() {
111
			wp_enqueue_style( 'jetpack-simple-payments-widget-style', plugins_url( 'simple-payments/style.css', __FILE__ ), array(), '20180518' );
112
		}
113
114
		function admin_enqueue_styles_and_scripts(){
115
				wp_enqueue_style( 'jetpack-simple-payments-widget-customizer', plugins_url( 'simple-payments/customizer.css', __FILE__ ) );
116
117
				wp_enqueue_media();
118
				wp_enqueue_script( 'jetpack-simple-payments-widget-customizer', plugins_url( '/simple-payments/customizer.js', __FILE__ ), array( 'jquery' ), false, true );
119
				wp_localize_script( 'jetpack-simple-payments-widget-customizer', 'jpSimplePaymentsStrings', array(
120
					'deleteConfirmation' => __( 'Are you sure you want to delete this item? It will be disabled and removed from all locations where it currently appears.', 'jetpack' )
121
				) );
122
		}
123
124
		public function ajax_get_payment_buttons() {
125
			if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
126
				wp_send_json_error( 'bad_nonce', 400 );
127
			}
128
129
			if ( ! current_user_can( 'customize' ) ) {
130
				wp_send_json_error( 'customize_not_allowed', 403 );
131
			}
132
133
			$post_type_object = get_post_type_object( Jetpack_Simple_Payments::$post_type_product );
0 ignored issues
show
Bug introduced by
The property post_type_product cannot be accessed from this context as it is declared private in class Jetpack_Simple_Payments.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
134 View Code Duplication
			if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
135
				wp_send_json_error( 'insufficient_post_permissions', 403 );
136
			}
137
138
			$product_posts = get_posts( array(
139
				'numberposts' => 100,
140
				'orderby' => 'date',
141
				'post_type' => Jetpack_Simple_Payments::$post_type_product,
0 ignored issues
show
Bug introduced by
The property post_type_product cannot be accessed from this context as it is declared private in class Jetpack_Simple_Payments.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
142
				'post_status' => 'publish',
143
			 ) );
144
145
			 $formatted_products = array_map( array( $this, 'format_product_post_for_ajax_reponse' ), $product_posts );
146
147
			 wp_send_json_success( $formatted_products );
148
		}
149
150
		public function format_product_post_for_ajax_reponse( $product_post ) {
151
			return array(
152
				'ID' => $product_post->ID,
153
				'post_title' => $product_post->post_title,
154
			);
155
		}
156
157
		public function ajax_save_payment_button() {
158
			if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
159
				wp_send_json_error( 'bad_nonce', 400 );
160
			}
161
162
			if ( ! current_user_can( 'customize' ) ) {
163
				wp_send_json_error( 'customize_not_allowed', 403 );
164
			}
165
166
			$post_type_object = get_post_type_object( Jetpack_Simple_Payments::$post_type_product );
0 ignored issues
show
Bug introduced by
The property post_type_product cannot be accessed from this context as it is declared private in class Jetpack_Simple_Payments.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
167 View Code Duplication
			if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
168
				wp_send_json_error( 'insufficient_post_permissions', 403 );
169
			}
170
171 View Code Duplication
			if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
172
				wp_send_json_error( 'missing_params', 400 );
173
			}
174
175
			$params = wp_unslash( $_POST['params'] );
176
			$errors = $this->validate_ajax_params( $params );
177
			if ( ! empty( $errors->errors ) ) {
178
				wp_send_json_error( $errors );
179
			}
180
181
			$product_post_id = isset( $params['product_post_id'] ) ? intval( $params['product_post_id'] ) : 0;
182
183
			$product_post = array(
184
				'ID' => $product_post_id,
185
				'post_type' => Jetpack_Simple_Payments::$post_type_product,
0 ignored issues
show
Bug introduced by
The property post_type_product cannot be accessed from this context as it is declared private in class Jetpack_Simple_Payments.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
186
				'post_status' => 'publish',
187
				'post_title' => $params['post_title'],
188
				'post_content' => $params['post_content'],
189
				'_thumbnail_id' => ! empty( $params['image_id'] ) ? $params['image_id'] : -1,
190
				'meta_input' => array(
191
					'spay_currency' => $params['currency'],
192
					'spay_price' => $params['price'],
193
					'spay_multiple' => isset( $params['multiple'] ) ? intval( $params['multiple'] ) : 0,
194
					'spay_email' => is_email( $params['email'] ),
195
				),
196
			);
197
198
			if ( empty( $product_post_id ) ) {
199
				$product_post_id = wp_insert_post( $product_post );
200
			} else {
201
				$product_post_id = wp_update_post( $product_post );
202
			}
203
204
			if ( ! $product_post_id || is_wp_error( $product_post_id ) ) {
205
				wp_send_json_error( $product_post_id );
206
			}
207
208
			wp_send_json_success( [
209
				'product_post_id' => $product_post_id,
210
				'product_post_title' => $params['post_title'],
211
			] );
212
		}
213
214
		public function ajax_delete_payment_button() {
215
			if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
216
				wp_send_json_error( 'bad_nonce', 400 );
217
			}
218
219
			if ( ! current_user_can( 'customize' ) ) {
220
				wp_send_json_error( 'customize_not_allowed', 403 );
221
			}
222
223 View Code Duplication
			if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
224
				wp_send_json_error( 'missing_params', 400 );
225
			}
226
227
			$params = wp_unslash( $_POST['params'] );
228
			$illegal_params = array_diff( array_keys( $params ), array( 'product_post_id' ) );
229
			if ( ! empty( $illegal_params ) ) {
230
				wp_send_json_error( 'illegal_params', 400 );
231
			}
232
233
			$product_id = ( int ) $params['product_post_id'];
234
			$product_post = get_post( $product_id );
235
236
			$return = array( 'status' => $product_post->post_status );
237
238
			wp_delete_post( $product_id, true );
239
			$status = get_post_status( $product_id );
240
			if ( false === $status ) {
241
				$return['status'] = 'deleted';
242
			}
243
244
			wp_send_json_success( $return );
245
		}
246
247
		public function validate_ajax_params( $params ) {
248
			$errors = new WP_Error();
249
250
			$illegal_params = array_diff( array_keys( $params ), array( 'product_post_id', 'post_title', 'post_content', 'image_id', 'currency', 'price', 'multiple', 'email' ) );
251
			if ( ! empty( $illegal_params ) ) {
252
				$errors.add( 'illegal_params' );
253
			}
254
255
			if ( empty( $params['post_title'] ) ) {
256
				$errors->add( 'post_title', __( 'People need to know what they\'re paying for! Please add a brief title.' ) );
257
			}
258
259
			if ( empty( $params['price'] ) || intval( $params['price'] ) < 0 ) {
260
				$errors->add( 'price', __( 'Everything comes with a price tag these days. Please add a your product price.' ) );
261
			}
262
263
			if ( empty( $params['email'] ) || ! is_email( $params['email'] ) ) {
264
				$errors->add( 'email', __( 'We want to make sure payments reach you, so please add an email address.' ) );
265
			}
266
267
			return $errors;
268
		}
269
270
		/**
271
		 * Front-end display of widget.
272
		 *
273
		 * @see WP_Widget::widget()
274
		 *
275
		 * @param array $args     Widget arguments.
276
		 * @param array $instance Saved values from database.
277
		 */
278
		function widget( $args, $instance ) {
279
			$instance = wp_parse_args( $instance, $this->defaults() );
280
281
			echo $args['before_widget'];
282
283
			/** This filter is documented in core/src/wp-includes/default-widgets.php */
284
			$title = apply_filters( 'widget_title', $instance['title'] );
285
			if ( ! empty( $title ) ) {
286
				echo $args['before_title'] . $title . $args['after_title'];
287
			}
288
289
			echo '<div class="jetpack-simple-payments-content">';
290
291
			if ( ! empty( $instance['form_action'] ) && in_array( $instance['form_action'], array( 'add', 'edit' ) ) && is_customize_preview() ) {
292
				require( dirname( __FILE__ ) . '/simple-payments/widget.php' );
293
			} else {
294
				if ( ! empty( $instance['product_post_id'] ) ) {
295
					$attrs = array( 'id' => $instance['product_post_id'] );
296
				} else {
297
					$product_posts = get_posts( array(
298
						'numberposts' => 1,
299
						'orderby' => 'date',
300
						'post_type' => Jetpack_Simple_Payments::$post_type_product,
0 ignored issues
show
Bug introduced by
The property post_type_product cannot be accessed from this context as it is declared private in class Jetpack_Simple_Payments.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
301
						'post_status' => 'publish',
302
					 ) );
303
	
304
					$attrs = array( 'id' => $product_posts[0]->ID );
305
				}
306
307
				$jsp = Jetpack_Simple_Payments::getInstance();
308
				$simple_payments_button = $jsp->parse_shortcode( $attrs );
309
				if ( is_null( $simple_payments_button ) && ! is_customize_preview() ) {
310
					return;
311
				}
312
313
				echo $simple_payments_button;
314
			}
315
316
			echo '</div><!--simple-payments-->';
317
318
			echo $args['after_widget'];
319
320
			/** This action is already documented in modules/widgets/gravatar-profile.php */
321
			do_action( 'jetpack_stats_extra', 'widget_view', 'simple_payments' );
322
		}
323
324
		/**
325
		 * Gets the latests field value from either the old instance or the new instance.
326
		 *
327
		 * @param array $mixed Array of values for the new form instance.
0 ignored issues
show
Bug introduced by
There is no parameter named $mixed. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
328
		 * @param array $mixed Array of values for the old form instance.
0 ignored issues
show
Bug introduced by
There is no parameter named $mixed. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
329
		 * @return mixed $mixed Field value.
330
		 */
331
		private function get_latest_field_value( $new_instance, $old_instance, $field) {
332
			return ! empty( $new_instance[ $field ] )
333
				? sanitize_text_field( $new_instance[ $field ] )
334
				: $old_instance[ $field ];
335
		}
336
337
		/**
338
		 * Gets the product fields from the product post. If no post found
339
		 * it returns the default values.
340
		 *
341
		 * @param int Product Post ID.
342
		 * @return array $fields Product Fields from the Product Post.
343
		 */
344
		private function get_product_from_post( $product_post_id ) {
345
			$product_post = get_post( $product_post_id );
346
			$form_product_id = $product_post_id;
347
			if( ! empty( $product_post ) ) {
348
				$form_product_image_id = get_post_thumbnail_id( $product_post_id );
349
350
				return array(
351
					'form_product_id' => $form_product_id,
352
					'form_product_title' => get_the_title( $product_post ),
353
					'form_product_description' => $product_post->post_content,
354
					'form_product_image_id' => $form_product_image_id,
355
					'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
356
					'form_product_currency' => get_post_meta( $product_post_id, 'spay_currency', true ),
357
					'form_product_price' => get_post_meta( $product_post_id, 'spay_price', true ),
358
					'form_product_multiple' => get_post_meta( $product_post_id, 'spay_multiple', true ) || '0',
359
					'form_product_email' => get_post_meta( $product_post_id, 'spay_email', true ),
360
				);
361
			}
362
363
			return $this->defaults();
364
		}
365
366
		/**
367
		 * Sanitize widget form values as they are saved.
368
		 *
369
		 * @see WP_Widget::update()
370
		 *
371
		 * @param array $new_instance Values just sent to be saved.
372
		 * @param array $old_instance Previously saved values from database.
373
		 *
374
		 * @return array Updated safe values to be saved.
375
		 */
376
		function update( $new_instance, $old_instance ) {
377
			$new_instance = wp_parse_args( $new_instance, $this->defaults() );
378
			$old_instance = wp_parse_args( $old_instance, $this->defaults() );
379
380
			$required_widget_props = array(
381
				'title' => $this->get_latest_field_value( $new_instance, $old_instance, 'title' ),
382
				'product_post_id' => $this->get_latest_field_value( $new_instance, $old_instance, 'product_post_id' ),
383
				'form_action' => $this->get_latest_field_value( $new_instance, $old_instance, 'form_action' ),
384
			);
385
386
			if ( strcmp( $new_instance['form_action'], $old_instance['form_action'] ) !== 0 ) {
387
				if ( $new_instance['form_action'] == 'edit' ) {
388
					return array_merge( $this->get_product_from_post( ( int ) $old_instance['product_post_id'] ), $required_widget_props );
389
				}
390
391
				if ( $new_instance['form_action'] == 'clear' ) {
392
					return array_merge( $this->defaults(), $required_widget_props );
393
				}
394
			}
395
396
			$form_product_image_id = (int) $new_instance['form_product_image_id'];
397
398
			$form_product_email = ! empty( $new_instance['form_product_email'] )
399
				? sanitize_text_field( $new_instance['form_product_email'] )
400
				: $this->defaults()['form_product_email'];
401
402
			return array_merge( $required_widget_props, array(
403
				'form_product_id' => ( int ) $new_instance['form_product_id'],
404
				'form_product_title' => sanitize_text_field( $new_instance['form_product_title'] ),
405
				'form_product_description' => sanitize_text_field( $new_instance['form_product_description'] ),
406
				'form_product_image_id' => $form_product_image_id,
407
				'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
408
				'form_product_currency' => sanitize_text_field( $new_instance['form_product_currency'] ),
409
				'form_product_price' => sanitize_text_field( $new_instance['form_product_price'] ),
410
				'form_product_multiple' => sanitize_text_field( $new_instance['form_product_multiple'] ),
411
				'form_product_email' => $form_product_email,
412
			) );
413
		}
414
415
		/**
416
		 * Back-end widget form.
417
		 *
418
		 * @see WP_Widget::form()
419
		 *
420
		 * @param array $instance Previously saved values from database.
421
		 */
422
		function form( $instance ) {
423
			$instance = wp_parse_args( $instance, $this->defaults() );
424
425
			$product_posts = get_posts( array(
426
				'numberposts' => 100,
427
				'orderby' => 'date',
428
				'post_type' => Jetpack_Simple_Payments::$post_type_product,
0 ignored issues
show
Bug introduced by
The property post_type_product cannot be accessed from this context as it is declared private in class Jetpack_Simple_Payments.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
429
				'post_status' => 'publish',
430
			 ) );
431
432
			require( dirname( __FILE__ ) . '/simple-payments/form.php' );
433
		}
434
	}
435
436
	// Register Jetpack_Simple_Payments_Widget widget.
437
	function register_widget_jetpack_simple_payments() {
438
		if ( ! Jetpack::is_active() ) {
439
			return;
440
		}
441
442
		register_widget( 'Jetpack_Simple_Payments_Widget' );
443
	}
444
	add_action( 'widgets_init', 'register_widget_jetpack_simple_payments' );
445
}
446