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