Completed
Push — add/simple-payments-widget-for... ( d02aef...a8417f )
by
unknown
52:45 queued 42:44
created

Jetpack_Simple_Payments_Widget::widget()   C

Complexity

Conditions 8
Paths 10

Size

Total Lines 45
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 27
nc 10
nop 2
dl 0
loc 45
rs 5.3846
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-button-save', array( $this, 'ajax_save_payment_button' ) );
64
				add_action( 'wp_ajax_customize-jetpack-simple-payments-button-delete', array( $this, 'ajax_delete_payment_button' ) );
65
			}
66
67
			if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
68
				add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
69
			}
70
		}
71
72
		/**
73
		 * Return an associative array of default values.
74
		 *
75
		 * These values are used in new widgets.
76
		 *
77
		 * @return array Default values for the widget options.
78
		 */
79
		private function defaults() {
80
			$current_user = wp_get_current_user();
81
82
			return array(
83
				'title' => '',
84
				'product_post_id' => 0,
85
				'form_action' => '',
86
				'form_product_id' => 0,
87
				'form_product_title' => '',
88
				'form_product_description' => '',
89
				'form_product_image_id' => 0,
90
				'form_product_image_src' => '',
91
				'form_product_currency' => '',
92
				'form_product_price' => '',
93
				'form_product_multiple' => '',
94
				'form_product_email' => $current_user->user_email,
95
			);
96
		}
97
98
		/**
99
		 * Adds a nonce for customizing menus.
100
		 *
101
		 * @param array $nonces Array of nonces.
102
		 * @return array $nonces Modified array of nonces.
103
		 */
104
		function filter_nonces( $nonces ) {
105
			$nonces['customize-jetpack-simple-payments'] = wp_create_nonce( 'customize-jetpack-simple-payments' );
106
			return $nonces;
107
		}
108
109
		function enqueue_style() {
110
			wp_enqueue_style( 'jetpack-simple-payments-widget-style', plugins_url( 'simple-payments/style.css', __FILE__ ), array(), '20180518' );
111
		}
112
113
		function admin_enqueue_styles_and_scripts(){
114
				wp_enqueue_style( 'jetpack-simple-payments-widget-customizer', plugins_url( 'simple-payments/customizer.css', __FILE__ ) );
115
116
				wp_enqueue_media();
117
				wp_enqueue_script( 'jetpack-simple-payments-widget-customizer', plugins_url( '/simple-payments/customizer.js', __FILE__ ), array( 'jquery' ), false, true );
118
				wp_localize_script( 'jetpack-simple-payments-widget-customizer', 'jpSimplePaymentsStrings', array(
119
					'deleteConfirmation' => __( 'Are you sure you want to delete this item? It will be disabled and removed from all locations where it currently appears.', 'jetpack' )
120
				) );
121
		}
122
123
		public function ajax_save_payment_button() {
124
			if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
125
				wp_send_json_error( 'bad_nonce', 400 );
126
			}
127
128
			if ( ! current_user_can( 'customize' ) ) {
129
				wp_send_json_error( 'customize_not_allowed', 403 );
130
			}
131
132
			$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...
133
			if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
134
				wp_send_json_error( 'insufficient_post_permissions', 403 );
135
			}
136
137 View Code Duplication
			if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
138
				wp_send_json_error( 'missing_params', 400 );
139
			}
140
141
			$params = wp_unslash( $_POST['params'] );
142
			$illegal_params = array_diff( array_keys( $params ), array( 'product_post_id', 'post_title', 'post_content', 'image_id', 'currency', 'price', 'multiple', 'email' ) );
143
			if ( ! empty( $illegal_params ) ) {
144
				wp_send_json_error( 'illegal_params', 400 );
145
			}
146
147
			$product_post_id = isset( $params['product_post_id'] ) ? intval( $params['product_post_id'] ) : 0;
148
149
			$product_post = array(
150
				'ID' => $product_post_id,
151
				'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...
152
				'post_status' => 'publish',
153
				'post_title' => $params['post_title'],
154
				'post_content' => $params['post_content'],
155
				'_thumbnail_id' => ! empty( $params['image_id'] ) ? $params['image_id'] : -1,
156
				'meta_input' => array(
157
					'spay_currency' => $params['currency'],
158
					'spay_price' => $params['price'],
159
					'spay_multiple' => isset( $params['multiple'] ) ? intval( $params['multiple'] ) : 0,
160
					'spay_email' => is_email( $params['email'] ),
161
				),
162
			);
163
164
			if ( empty( $product_post_id ) ) {
165
				$product_post_id = wp_insert_post( $product_post );
166
			} else {
167
				$product_post_id = wp_update_post( $product_post );
168
			}
169
170
			if ( ! $product_post_id || is_wp_error( $product_post_id ) ) {
171
				wp_send_json_error( $product_post_id );
172
			}
173
174
			wp_send_json_success( [
175
				'product_post_id' => $product_post_id,
176
				'product_post_title' => $params['post_title'],
177
			] );
178
		}
179
180
		public function ajax_delete_payment_button() {
181
			if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
182
				wp_send_json_error( 'bad_nonce', 400 );
183
			}
184
185
			if ( ! current_user_can( 'customize' ) ) {
186
				wp_send_json_error( 'customize_not_allowed', 403 );
187
			}
188
189 View Code Duplication
			if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
190
				wp_send_json_error( 'missing_params', 400 );
191
			}
192
193
			$params = wp_unslash( $_POST['params'] );
194
			$illegal_params = array_diff( array_keys( $params ), array( 'product_post_id' ) );
195
			if ( ! empty( $illegal_params ) ) {
196
				wp_send_json_error( 'illegal_params', 400 );
197
			}
198
199
			$product_id = ( int ) $params['product_post_id'];
200
			$product_post = get_post( $product_id );
201
202
			$return = array( 'status' => $product_post->post_status );
203
204
			wp_delete_post( $product_id, true );
205
			$status = get_post_status( $product_id );
206
			if ( false === $status ) {
207
				$return['status'] = 'deleted';
208
			}
209
210
			wp_send_json_success( $return );
211
		}
212
213
		public function validate_ajax_params( $params ) {
214
			$errors = new WP_Error();
215
216
			$illegal_params = array_diff( array_keys( $params ), array( 'product_post_id', 'post_title', 'post_content', 'image_id', 'currency', 'price', 'multiple', 'email' ) );
217
			if ( ! empty( $illegal_params ) ) {
218
				$errors.add( 'illegal_params' );
219
			}
220
221
			if ( empty( $params['post_title'] ) ) {
222
				$errors->add( 'post_title', __( 'People need to know what they\'re paying for! Please add a brief title.' ) );
223
			}
224
225
			if ( empty( $params['price'] ) || intval( $params['price'] ) > 0 ) {
226
				$errors->add( 'price', __( 'Everything comes with a price tag these days. Please add a your product price.' ) );
227
			}
228
229
			if ( empty( $params['email'] ) || ! is_email( $params['email'] ) ) {
230
				$errors->add( 'email', __( 'We want to make sure payments reach you, so please add an email address.' ) );
231
			}
232
233
			return $errors;
234
		}
235
		/**
236
		 * Front-end display of widget.
237
		 *
238
		 * @see WP_Widget::widget()
239
		 *
240
		 * @param array $args     Widget arguments.
241
		 * @param array $instance Saved values from database.
242
		 */
243
		function widget( $args, $instance ) {
244
			$instance = wp_parse_args( $instance, $this->defaults() );
245
246
			echo $args['before_widget'];
247
248
			/** This filter is documented in core/src/wp-includes/default-widgets.php */
249
			$title = apply_filters( 'widget_title', $instance['title'] );
250
			if ( ! empty( $title ) ) {
251
				echo $args['before_title'] . $title . $args['after_title'];
252
			}
253
254
			echo '<div class="jetpack-simple-payments-content">';
255
256
			if ( ! empty( $instance['form_action'] ) && in_array( $instance['form_action'], array( 'add', 'edit' ) ) && is_customize_preview() ) {
257
				require( dirname( __FILE__ ) . '/simple-payments/widget.php' );
258
			} else {
259
				if ( ! empty( $instance['product_post_id'] ) ) {
260
					$attrs = array( 'id' => $instance['product_post_id'] );
261
				} else {
262
					$product_posts = get_posts( array(
263
						'numberposts' => 1,
264
						'orderby' => 'date',
265
						'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...
266
						'post_status' => 'publish',
267
					 ) );
268
	
269
					$attrs = array( 'id' => $product_posts[0]->ID );
270
				}
271
272
				$jsp = Jetpack_Simple_Payments::getInstance();
273
				$simple_payments_button = $jsp->parse_shortcode( $attrs );
274
				if ( is_null( $simple_payments_button ) && ! is_customize_preview() ) {
275
					return;
276
				}
277
278
				echo $simple_payments_button;
279
			}
280
281
			echo '</div><!--simple-payments-->';
282
283
			echo $args['after_widget'];
284
285
			/** This action is already documented in modules/widgets/gravatar-profile.php */
286
			do_action( 'jetpack_stats_extra', 'widget_view', 'simple_payments' );
287
		}
288
289
		/**
290
		 * Gets the latests field value from either the old instance or the new instance.
291
		 *
292
		 * @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...
293
		 * @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...
294
		 * @return mixed $mixed Field value.
295
		 */
296
		private function get_latest_field_value( $new_instance, $old_instance, $field) {
297
			return ! empty( $new_instance[ $field ] )
298
				? sanitize_text_field( $new_instance[ $field ] )
299
				: $old_instance[ $field ];
300
		}
301
302
		/**
303
		 * Gets the product fields from the product post. If no post found
304
		 * it returns the default values.
305
		 *
306
		 * @param int Product Post ID.
307
		 * @return array $fields Product Fields from the Product Post.
308
		 */
309
		private function get_product_from_post( $product_post_id ) {
310
			$product_post = get_post( $product_post_id );
311
			$form_product_id = $product_post_id;
312
			if( ! empty( $product_post ) ) {
313
				$form_product_image_id = get_post_thumbnail_id( $product_post_id );
314
315
				return array(
316
					'form_product_id' => $form_product_id,
317
					'form_product_title' => get_the_title( $product_post ),
318
					'form_product_description' => $product_post->post_content,
319
					'form_product_image_id' => $form_product_image_id,
320
					'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
321
					'form_product_currency' => get_post_meta( $product_post_id, 'spay_currency', true ),
322
					'form_product_price' => get_post_meta( $product_post_id, 'spay_price', true ),
323
					'form_product_multiple' => get_post_meta( $product_post_id, 'spay_multiple', true ) || '0',
324
					'form_product_email' => get_post_meta( $product_post_id, 'spay_email', true ),
325
				);
326
			}
327
328
			return $this->defaults();
329
		}
330
331
		/**
332
		 * Sanitize widget form values as they are saved.
333
		 *
334
		 * @see WP_Widget::update()
335
		 *
336
		 * @param array $new_instance Values just sent to be saved.
337
		 * @param array $old_instance Previously saved values from database.
338
		 *
339
		 * @return array Updated safe values to be saved.
340
		 */
341
		function update( $new_instance, $old_instance ) {
342
			$new_instance = wp_parse_args( $new_instance, $this->defaults() );
343
			$old_instance = wp_parse_args( $old_instance, $this->defaults() );
344
345
			$required_widget_props = array(
346
				'title' => $this->get_latest_field_value( $new_instance, $old_instance, 'title' ),
347
				'product_post_id' => $this->get_latest_field_value( $new_instance, $old_instance, 'product_post_id' ),
348
				'form_action' => $this->get_latest_field_value( $new_instance, $old_instance, 'form_action' ),
349
			);
350
351
			if ( strcmp( $new_instance['form_action'], $old_instance['form_action'] ) !== 0 ) {
352
				if ( $new_instance['form_action'] == 'edit' ) {
353
					return array_merge( $this->get_product_from_post( ( int ) $old_instance['product_post_id'] ), $required_widget_props );
354
				}
355
356
				if ( $new_instance['form_action'] == 'clear' ) {
357
					return array_merge( $this->defaults(), $required_widget_props );
358
				}
359
			}
360
361
			$form_product_image_id = (int) $new_instance['form_product_image_id'];
362
363
			$form_product_email = ! empty( $new_instance['form_product_email'] )
364
				? sanitize_text_field( $new_instance['form_product_email'] )
365
				: $this->defaults()['form_product_email'];
366
367
			return array_merge( $required_widget_props, array(
368
				'form_product_id' => ( int ) $new_instance['form_product_id'],
369
				'form_product_title' => sanitize_text_field( $new_instance['form_product_title'] ),
370
				'form_product_description' => sanitize_text_field( $new_instance['form_product_description'] ),
371
				'form_product_image_id' => $form_product_image_id,
372
				'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
373
				'form_product_currency' => sanitize_text_field( $new_instance['form_product_currency'] ),
374
				'form_product_price' => sanitize_text_field( $new_instance['form_product_price'] ),
375
				'form_product_multiple' => sanitize_text_field( $new_instance['form_product_multiple'] ),
376
				'form_product_email' => $form_product_email,
377
			) );
378
		}
379
380
		/**
381
		 * Back-end widget form.
382
		 *
383
		 * @see WP_Widget::form()
384
		 *
385
		 * @param array $instance Previously saved values from database.
386
		 */
387
		function form( $instance ) {
388
			$instance = wp_parse_args( $instance, $this->defaults() );
389
390
			$product_posts = get_posts( array(
391
				'numberposts' => 100,
392
				'orderby' => 'date',
393
				'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...
394
				'post_status' => 'publish',
395
			 ) );
396
397
			require( dirname( __FILE__ ) . '/simple-payments/form.php' );
398
		}
399
	}
400
401
	// Register Jetpack_Simple_Payments_Widget widget.
402
	function register_widget_jetpack_simple_payments() {
403
		if ( ! Jetpack::is_active() ) {
404
			return;
405
		}
406
407
		register_widget( 'Jetpack_Simple_Payments_Widget' );
408
	}
409
	add_action( 'widgets_init', 'register_widget_jetpack_simple_payments' );
410
}
411