Completed
Push — fix/disable-simple-payments-ed... ( b710e5...7c47cb )
by
unknown
35:26 queued 14:42
created

Jetpack_Simple_Payments_Widget::enqueue_style()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
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
			$default_product_id = $this->get_first_product_id();
82
83
			return array(
84
				'title' => '',
85
				'product_post_id' => $default_product_id,
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_save_payment_button() {
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
			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 View Code Duplication
			if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
139
				wp_send_json_error( 'missing_params', 400 );
140
			}
141
142
			$params = wp_unslash( $_POST['params'] );
143
			$errors = $this->validate_ajax_params( $params );
144
			if ( ! empty( $errors->errors ) ) {
145
				wp_send_json_error( $errors );
146
			}
147
148
			$product_post_id = isset( $params['product_post_id'] ) ? intval( $params['product_post_id'] ) : 0;
149
150
			$product_post = array(
151
				'ID' => $product_post_id,
152
				'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...
153
				'post_status' => 'publish',
154
				'post_title' => $params['post_title'],
155
				'post_content' => $params['post_content'],
156
				'_thumbnail_id' => ! empty( $params['image_id'] ) ? $params['image_id'] : -1,
157
				'meta_input' => array(
158
					'spay_currency' => $params['currency'],
159
					'spay_price' => $params['price'],
160
					'spay_multiple' => isset( $params['multiple'] ) ? intval( $params['multiple'] ) : 0,
161
					'spay_email' => is_email( $params['email'] ),
162
				),
163
			);
164
165
			if ( empty( $product_post_id ) ) {
166
				$product_post_id = wp_insert_post( $product_post );
167
			} else {
168
				$product_post_id = wp_update_post( $product_post );
169
			}
170
171
			if ( ! $product_post_id || is_wp_error( $product_post_id ) ) {
172
				wp_send_json_error( $product_post_id );
173
			}
174
175
			wp_send_json_success( [
176
				'product_post_id' => $product_post_id,
177
				'product_post_title' => $params['post_title'],
178
			] );
179
		}
180
181
		public function ajax_delete_payment_button() {
182
			if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
183
				wp_send_json_error( 'bad_nonce', 400 );
184
			}
185
186
			if ( ! current_user_can( 'customize' ) ) {
187
				wp_send_json_error( 'customize_not_allowed', 403 );
188
			}
189
190 View Code Duplication
			if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
191
				wp_send_json_error( 'missing_params', 400 );
192
			}
193
194
			$params = wp_unslash( $_POST['params'] );
195
			$illegal_params = array_diff( array_keys( $params ), array( 'product_post_id' ) );
196
			if ( ! empty( $illegal_params ) ) {
197
				wp_send_json_error( 'illegal_params', 400 );
198
			}
199
200
			$product_id = ( int ) $params['product_post_id'];
201
			$product_post = get_post( $product_id );
202
203
			$return = array( 'status' => $product_post->post_status );
204
205
			wp_delete_post( $product_id, true );
206
			$status = get_post_status( $product_id );
207
			if ( false === $status ) {
208
				$return['status'] = 'deleted';
209
			}
210
211
			wp_send_json_success( $return );
212
		}
213
214
		public function validate_ajax_params( $params ) {
215
			$errors = new WP_Error();
216
217
			$illegal_params = array_diff( array_keys( $params ), array( 'product_post_id', 'post_title', 'post_content', 'image_id', 'currency', 'price', 'multiple', 'email' ) );
218
			if ( ! empty( $illegal_params ) ) {
219
				$errors.add( 'illegal_params' );
220
			}
221
222
			if ( empty( $params['post_title'] ) ) {
223
				$errors->add( 'post_title', __( 'People need to know what they\'re paying for! Please add a brief title.' ) );
224
			}
225
226
			if ( empty( $params['price'] ) || intval( $params['price'] ) < 0 ) {
227
				$errors->add( 'price', __( 'Everything comes with a price tag these days. Please add a your product price.' ) );
228
			}
229
230
			if ( empty( $params['email'] ) || ! is_email( $params['email'] ) ) {
231
				$errors->add( 'email', __( 'We want to make sure payments reach you, so please add an email address.' ) );
232
			}
233
234
			return $errors;
235
		}
236
237
		function get_first_product_id() {
238
			$product_posts = get_posts( array(
239
				'numberposts' => 1,
240
				'orderby' => 'date',
241
				'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...
242
				'post_status' => 'publish',
243
			 ) );
244
245
			return ! empty( $product_posts ) ? $product_posts[0]->ID : null;
246
		}
247
248
		/**
249
		 * Front-end display of widget.
250
		 *
251
		 * @see WP_Widget::widget()
252
		 *
253
		 * @param array $args     Widget arguments.
254
		 * @param array $instance Saved values from database.
255
		 */
256
		function widget( $args, $instance ) {
257
			$instance = wp_parse_args( $instance, $this->defaults() );
258
259
			echo $args['before_widget'];
260
261
			/** This filter is documented in core/src/wp-includes/default-widgets.php */
262
			$title = apply_filters( 'widget_title', $instance['title'] );
263
			if ( ! empty( $title ) ) {
264
				echo $args['before_title'] . $title . $args['after_title'];
265
			}
266
267
			echo '<div class="jetpack-simple-payments-content">';
268
269
			if ( ! empty( $instance['form_action'] ) && in_array( $instance['form_action'], array( 'add', 'edit' ) ) && is_customize_preview() ) {
270
				require( dirname( __FILE__ ) . '/simple-payments/widget.php' );
271
			} else {
272
				$jsp = Jetpack_Simple_Payments::getInstance();
273
				$simple_payments_button = $jsp->parse_shortcode( array(
274
					'id' => $instance['product_post_id'],
275
				) );
276
277
				if ( ! is_null( $simple_payments_button ) || is_customize_preview() ) {
278
					echo $simple_payments_button;
279
				}
280
			}
281
282
			echo '</div><!--simple-payments-->';
283
284
			echo $args['after_widget'];
285
286
			/** This action is already documented in modules/widgets/gravatar-profile.php */
287
			do_action( 'jetpack_stats_extra', 'widget_view', 'simple_payments' );
288
		}
289
290
		/**
291
		 * Gets the latests field value from either the old instance or the new instance.
292
		 *
293
		 * @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...
294
		 * @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...
295
		 * @return mixed $mixed Field value.
296
		 */
297
		private function get_latest_field_value( $new_instance, $old_instance, $field) {
298
			return ! empty( $new_instance[ $field ] )
299
				? sanitize_text_field( $new_instance[ $field ] )
300
				: $old_instance[ $field ];
301
		}
302
303
		/**
304
		 * Gets the product fields from the product post. If no post found
305
		 * it returns the default values.
306
		 *
307
		 * @param int Product Post ID.
308
		 * @return array $fields Product Fields from the Product Post.
309
		 */
310
		private function get_product_from_post( $product_post_id ) {
311
			$product_post = get_post( $product_post_id );
312
			$form_product_id = $product_post_id;
313
			if( ! empty( $product_post ) ) {
314
				$form_product_image_id = get_post_thumbnail_id( $product_post_id );
315
316
				return array(
317
					'form_product_id' => $form_product_id,
318
					'form_product_title' => get_the_title( $product_post ),
319
					'form_product_description' => $product_post->post_content,
320
					'form_product_image_id' => $form_product_image_id,
321
					'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
322
					'form_product_currency' => get_post_meta( $product_post_id, 'spay_currency', true ),
323
					'form_product_price' => get_post_meta( $product_post_id, 'spay_price', true ),
324
					'form_product_multiple' => get_post_meta( $product_post_id, 'spay_multiple', true ) || '0',
325
					'form_product_email' => get_post_meta( $product_post_id, 'spay_email', true ),
326
				);
327
			}
328
329
			return $this->defaults();
330
		}
331
332
		/**
333
		 * Sanitize widget form values as they are saved.
334
		 *
335
		 * @see WP_Widget::update()
336
		 *
337
		 * @param array $new_instance Values just sent to be saved.
338
		 * @param array $old_instance Previously saved values from database.
339
		 *
340
		 * @return array Updated safe values to be saved.
341
		 */
342
		function update( $new_instance, $old_instance ) {
343
			$defaults = $this->defaults();
344
			//do not overrite `product_post_id` for `$new_instance` with the defaults
345
			$new_instance = wp_parse_args( $new_instance, array_diff_key( $defaults, array( 'product_post_id' => 0 ) ) );
346
			$old_instance = wp_parse_args( $old_instance, $defaults );
347
348
			$required_widget_props = array(
349
				'title' => $this->get_latest_field_value( $new_instance, $old_instance, 'title' ),
350
				'product_post_id' => $this->get_latest_field_value( $new_instance, $old_instance, 'product_post_id' ),
351
				'form_action' => $this->get_latest_field_value( $new_instance, $old_instance, 'form_action' ),
352
			);
353
354
			if ( strcmp( $new_instance['form_action'], $old_instance['form_action'] ) !== 0 ) {
355
				if ( $new_instance['form_action'] == 'edit' ) {
356
					return array_merge( $this->get_product_from_post( ( int ) $old_instance['product_post_id'] ), $required_widget_props );
357
				}
358
359
				if ( $new_instance['form_action'] == 'clear' ) {
360
					return array_merge( $this->defaults(), $required_widget_props );
361
				}
362
			}
363
364
			$form_product_image_id = (int) $new_instance['form_product_image_id'];
365
366
			$form_product_email = ! empty( $new_instance['form_product_email'] )
367
				? sanitize_text_field( $new_instance['form_product_email'] )
368
				: $this->defaults()['form_product_email'];
369
370
			return array_merge( $required_widget_props, array(
371
				'form_product_id' => ( int ) $new_instance['form_product_id'],
372
				'form_product_title' => sanitize_text_field( $new_instance['form_product_title'] ),
373
				'form_product_description' => sanitize_text_field( $new_instance['form_product_description'] ),
374
				'form_product_image_id' => $form_product_image_id,
375
				'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
376
				'form_product_currency' => sanitize_text_field( $new_instance['form_product_currency'] ),
377
				'form_product_price' => sanitize_text_field( $new_instance['form_product_price'] ),
378
				'form_product_multiple' => sanitize_text_field( $new_instance['form_product_multiple'] ),
379
				'form_product_email' => $form_product_email,
380
			) );
381
		}
382
383
		/**
384
		 * Back-end widget form.
385
		 *
386
		 * @see WP_Widget::form()
387
		 *
388
		 * @param array $instance Previously saved values from database.
389
		 */
390
		function form( $instance ) {
391
			$instance = wp_parse_args( $instance, $this->defaults() );
392
393
			$product_posts = get_posts( array(
394
				'numberposts' => 100,
395
				'orderby' => 'date',
396
				'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...
397
				'post_status' => 'publish',
398
			 ) );
399
400
			require( dirname( __FILE__ ) . '/simple-payments/form.php' );
401
		}
402
	}
403
404
	// Register Jetpack_Simple_Payments_Widget widget.
405
	function register_widget_jetpack_simple_payments() {
406
		if ( ! Jetpack::is_active() ) {
407
			return;
408
		}
409
410
		register_widget( 'Jetpack_Simple_Payments_Widget' );
411
	}
412
	add_action( 'widgets_init', 'register_widget_jetpack_simple_payments' );
413
}
414