PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.7.3
Jetpack – WP Security, Backup, Speed, & Growth v12.7.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 2 years ago facebook-likebox 11 years ago flickr 2 years ago gallery 4 years ago goodreads 5 years ago google-translate 4 years ago image-widget 8 years ago instagram 6 years ago internet-defense-league 3 years ago migrate-to-core 3 years ago milestone 2 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 2 years ago class-jetpack-eu-cookie-law-widget.php 3 years ago class-jetpack-instagram-widget.php 2 years ago contact-info.php 2 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 2 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 2 years ago rsslinks-widget.php 3 years ago simple-payments.php 2 years ago social-icons.php 2 years ago social-media-icons.php 3 years ago top-posts.php 2 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
625 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 // Disable direct access/execution to/of the widget code.
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 if ( ! class_exists( 'Jetpack_Simple_Payments_Widget' ) ) {
13 /**
14 * Pay with PayPal (aka Simple Payments)
15 *
16 * Display a Pay with PayPal button as a Widget.
17 */
18 class Jetpack_Simple_Payments_Widget extends WP_Widget {
19 /**
20 * Currencies should be supported by PayPal:
21 *
22 * @var array $supported_currency_list
23 * @link https://developer.paypal.com/docs/api/reference/currency-codes/
24 *
25 * List has to be in sync with list at the block's client side and API's backend side:
26 * @link https://github.com/Automattic/jetpack/blob/31efa189ad223c0eb7ad085ac0650a23facf9ef5/extensions/blocks/simple-payments/constants.js#L9-L39
27 * @link https://github.com/Automattic/jetpack/blob/31efa189ad223c0eb7ad085ac0650a23facf9ef5/modules/simple-payments/simple-payments.php#L386-L415
28 *
29 * Indian Rupee (INR) is listed here for backwards compatibility with previously added widgets.
30 * It's not supported by Pay with PayPal because at the time of the creation of this file
31 * because it's limited to in-country PayPal India accounts only.
32 * Discussion: https://github.com/Automattic/wp-calypso/pull/28236
33 */
34 private static $supported_currency_list = array(
35 'USD' => '$',
36 'GBP' => '&#163;',
37 'JPY' => '&#165;',
38 'BRL' => 'R$',
39 'EUR' => '&#8364;',
40 'NZD' => 'NZ$',
41 'AUD' => 'A$',
42 'CAD' => 'C$',
43 'INR' => '',
44 'ILS' => '',
45 'RUB' => '',
46 'MXN' => 'MX$',
47 'SEK' => 'Skr',
48 'HUF' => 'Ft',
49 'CHF' => 'CHF',
50 'CZK' => '',
51 'DKK' => 'Dkr',
52 'HKD' => 'HK$',
53 'NOK' => 'Kr',
54 'PHP' => '',
55 'PLN' => 'PLN',
56 'SGD' => 'S$',
57 'TWD' => 'NT$',
58 'THB' => '฿',
59 );
60
61 /**
62 * Constructor.
63 */
64 public function __construct() {
65 parent::__construct(
66 'jetpack_simple_payments_widget',
67 /** This filter is documented in modules/widgets/facebook-likebox.php */
68 apply_filters( 'jetpack_widget_name', __( 'Pay with PayPal', 'jetpack' ) ),
69 array(
70 'classname' => 'jetpack-simple-payments',
71 'description' => __( 'Add a Pay with PayPal button as a Widget.', 'jetpack' ),
72 'customize_selective_refresh' => true,
73 )
74 );
75
76 global $pagenow;
77 if ( is_customize_preview() || 'widgets.php' === $pagenow ) {
78 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_styles' ) );
79 }
80
81 $jetpack_simple_payments = Jetpack_Simple_Payments::get_instance();
82 if ( is_customize_preview() && $jetpack_simple_payments->is_enabled_jetpack_simple_payments() ) {
83 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
84
85 add_filter( 'customize_refresh_nonces', array( $this, 'filter_nonces' ) );
86 add_action( 'wp_ajax_customize-jetpack-simple-payments-buttons-get', array( $this, 'ajax_get_payment_buttons' ) );
87 add_action( 'wp_ajax_customize-jetpack-simple-payments-button-save', array( $this, 'ajax_save_payment_button' ) );
88 add_action( 'wp_ajax_customize-jetpack-simple-payments-button-delete', array( $this, 'ajax_delete_payment_button' ) );
89 }
90
91 if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
92 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );
93 }
94
95 add_filter( 'widget_types_to_hide_from_legacy_widget_block', array( $this, 'hide_simple_payment_widget' ) );
96 }
97
98 /**
99 * Return an array of the widgets hidden from the Legacy Widget block.
100 *
101 * This is used to hide the Pay with PayPal from the Legacy Widget block.
102 *
103 * @param array $widget_types the widget types that are currently hidden.
104 * @return array Widget types hidden from the Legacy Widget block
105 */
106 public function hide_simple_payment_widget( $widget_types ) {
107 $widget_types[] = 'jetpack_simple_payments_widget';
108 return $widget_types;
109 }
110
111 /**
112 * Return an associative array of default values.
113 *
114 * These values are used in new widgets.
115 *
116 * @return array Default values for the widget options.
117 */
118 private function defaults() {
119 $current_user = wp_get_current_user();
120 $default_product_id = $this->get_first_product_id();
121
122 return array(
123 'title' => '',
124 'product_post_id' => $default_product_id,
125 'form_action' => '',
126 'form_product_id' => 0,
127 'form_product_title' => '',
128 'form_product_description' => '',
129 'form_product_image_id' => 0,
130 'form_product_image_src' => '',
131 'form_product_currency' => '',
132 'form_product_price' => '',
133 'form_product_multiple' => '',
134 'form_product_email' => $current_user->user_email,
135 );
136 }
137
138 /**
139 * Adds a nonce for customizing menus.
140 *
141 * @param array $nonces Array of nonces.
142 * @return array $nonces Modified array of nonces.
143 */
144 public function filter_nonces( $nonces ) {
145 $nonces['customize-jetpack-simple-payments'] = wp_create_nonce( 'customize-jetpack-simple-payments' );
146 return $nonces;
147 }
148
149 /**
150 * Enqueue styles.
151 */
152 public function enqueue_style() {
153 wp_enqueue_style( 'jetpack-simple-payments-widget-style', plugins_url( 'simple-payments/style.css', __FILE__ ), array(), '20180518' );
154 }
155
156 /**
157 * Enqueue admin styles.
158 */
159 public function admin_enqueue_styles() {
160 wp_enqueue_style(
161 'jetpack-simple-payments-widget-customizer',
162 plugins_url( 'simple-payments/customizer.css', __FILE__ ),
163 array(),
164 JETPACK__VERSION
165 );
166 }
167
168 /**
169 * Enqueue admin scripts.
170 */
171 public function admin_enqueue_scripts() {
172 wp_enqueue_media();
173 wp_enqueue_script(
174 'jetpack-simple-payments-widget-customizer',
175 plugins_url( '/simple-payments/customizer.js', __FILE__ ),
176 array( 'jquery' ),
177 JETPACK__VERSION,
178 true
179 );
180 wp_localize_script(
181 'jetpack-simple-payments-widget-customizer',
182 'jpSimplePaymentsStrings',
183 array(
184 'deleteConfirmation' => __( 'Are you sure you want to delete this item? It will be disabled and removed from all locations where it currently appears.', 'jetpack' ),
185 )
186 );
187 }
188
189 /**
190 * Get payment buttons.
191 */
192 public function ajax_get_payment_buttons() {
193 if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
194 wp_send_json_error( 'bad_nonce', 400 );
195 }
196
197 if ( ! current_user_can( 'customize' ) ) {
198 wp_send_json_error( 'customize_not_allowed', 403 );
199 }
200
201 $post_type_object = get_post_type_object( Jetpack_Simple_Payments::$post_type_product );
202 if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
203 wp_send_json_error( 'insufficient_post_permissions', 403 );
204 }
205
206 $product_posts = get_posts(
207 array(
208 'numberposts' => 100,
209 'orderby' => 'date',
210 'post_type' => Jetpack_Simple_Payments::$post_type_product,
211 'post_status' => 'publish',
212 )
213 );
214
215 $formatted_products = array_map( array( $this, 'format_product_post_for_ajax_reponse' ), $product_posts );
216
217 wp_send_json_success( $formatted_products );
218 }
219
220 /**
221 * Format product_post object.
222 *
223 * @param object $product_post - info about the post the product is on.
224 */
225 public function format_product_post_for_ajax_reponse( $product_post ) {
226 return array(
227 'ID' => $product_post->ID,
228 'post_title' => $product_post->post_title,
229 );
230 }
231
232 /**
233 * Handle saving the simple payments widget.
234 */
235 public function ajax_save_payment_button() {
236 if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
237 wp_send_json_error( 'bad_nonce', 400 );
238 }
239
240 if ( ! current_user_can( 'customize' ) ) {
241 wp_send_json_error( 'customize_not_allowed', 403 );
242 }
243
244 $post_type_object = get_post_type_object( Jetpack_Simple_Payments::$post_type_product );
245 if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
246 wp_send_json_error( 'insufficient_post_permissions', 403 );
247 }
248
249 if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
250 wp_send_json_error( 'missing_params', 400 );
251 }
252
253 $params = wp_unslash( $_POST['params'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Manually validated by validate_ajax_params().
254 $errors = $this->validate_ajax_params( $params );
255 if ( ! empty( $errors->errors ) ) {
256 wp_send_json_error( $errors );
257 }
258
259 $product_post_id = isset( $params['product_post_id'] ) ? (int) $params['product_post_id'] : 0;
260
261 $product_post = array(
262 'ID' => $product_post_id,
263 'post_type' => Jetpack_Simple_Payments::$post_type_product,
264 'post_status' => 'publish',
265 'post_title' => $params['post_title'],
266 'post_content' => $params['post_content'],
267 '_thumbnail_id' => ! empty( $params['image_id'] ) ? $params['image_id'] : -1,
268 'meta_input' => array(
269 'spay_currency' => $params['currency'],
270 'spay_price' => $params['price'],
271 'spay_multiple' => isset( $params['multiple'] ) ? (int) $params['multiple'] : 0,
272 'spay_email' => is_email( $params['email'] ),
273 ),
274 );
275
276 if ( empty( $product_post_id ) ) {
277 $product_post_id = wp_insert_post( $product_post );
278 } else {
279 $product_post_id = wp_update_post( $product_post );
280 }
281
282 if ( ! $product_post_id || is_wp_error( $product_post_id ) ) {
283 wp_send_json_error( $product_post_id );
284 }
285
286 $tracks_properties = array(
287 'id' => $product_post_id,
288 'currency' => $params['currency'],
289 'price' => $params['price'],
290 );
291 if ( 0 === $product_post['ID'] ) {
292 $this->record_event( 'created', 'create', $tracks_properties );
293 } else {
294 $this->record_event( 'updated', 'update', $tracks_properties );
295 }
296
297 wp_send_json_success(
298 array(
299 'product_post_id' => $product_post_id,
300 'product_post_title' => $params['post_title'],
301 )
302 );
303 }
304
305 /**
306 * Handle deleting the simple payment widget.
307 */
308 public function ajax_delete_payment_button() {
309 if ( ! check_ajax_referer( 'customize-jetpack-simple-payments', 'customize-jetpack-simple-payments-nonce', false ) ) {
310 wp_send_json_error( 'bad_nonce', 400 );
311 }
312
313 if ( ! current_user_can( 'customize' ) ) {
314 wp_send_json_error( 'customize_not_allowed', 403 );
315 }
316
317 if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
318 wp_send_json_error( 'missing_params', 400 );
319 }
320
321 $params = wp_unslash( $_POST['params'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Manually validated just below.
322 $illegal_params = array_diff( array_keys( $params ), array( 'product_post_id' ) );
323 if ( ! empty( $illegal_params ) ) {
324 wp_send_json_error( 'illegal_params', 400 );
325 }
326
327 $product_id = (int) $params['product_post_id'];
328 $product_post = get_post( $product_id );
329
330 $return = array( 'status' => $product_post->post_status );
331
332 wp_delete_post( $product_id, true );
333 $status = get_post_status( $product_id );
334 if ( false === $status ) {
335 $return['status'] = 'deleted';
336 }
337
338 $this->record_event( 'deleted', 'delete', array( 'id' => $product_id ) );
339
340 wp_send_json_success( $return );
341 }
342
343 /**
344 * Returns the number of decimal places on string representing a price.
345 *
346 * @param string $number Price to check.
347 * @return number number of decimal places.
348 */
349 private function get_decimal_places( $number ) {
350 $parts = explode( '.', $number );
351 if ( count( $parts ) > 2 ) {
352 return null;
353 }
354
355 return isset( $parts[1] ) ? strlen( $parts[1] ) : 0;
356 }
357
358 /**
359 * Validate ajax parameters.
360 *
361 * @param array $params - the parameters.
362 */
363 public function validate_ajax_params( $params ) {
364 $errors = new WP_Error();
365
366 $illegal_params = array_diff( array_keys( $params ), array( 'product_post_id', 'post_title', 'post_content', 'image_id', 'currency', 'price', 'multiple', 'email' ) );
367 if ( ! empty( $illegal_params ) ) {
368 $errors->add( 'illegal_params', __( 'Invalid parameters.', 'jetpack' ) );
369 }
370
371 if ( empty( $params['post_title'] ) ) {
372 $errors->add( 'post_title', __( "People need to know what they're paying for! Please add a brief title.", 'jetpack' ) );
373 }
374
375 if ( empty( $params['price'] ) || ! is_numeric( $params['price'] ) || (float) $params['price'] <= 0 ) {
376 $errors->add( 'price', __( 'Everything comes with a price tag these days. Please add a your product price.', 'jetpack' ) );
377 }
378
379 // Japan's Yen is the only supported currency with a zero decimal precision.
380 $precision = strtoupper( $params['currency'] ) === 'JPY' ? 0 : 2;
381 $price_decimal_places = $this->get_decimal_places( $params['price'] );
382 if ( $price_decimal_places === null || $price_decimal_places > $precision ) {
383 $errors->add( 'price', __( 'Invalid price', 'jetpack' ) );
384 }
385
386 if ( empty( $params['email'] ) || ! is_email( $params['email'] ) ) {
387 $errors->add( 'email', __( 'We want to make sure payments reach you, so please add an email address.', 'jetpack' ) );
388 }
389
390 return $errors;
391 }
392
393 /**
394 * Get the id of the first product.
395 */
396 public function get_first_product_id() {
397 $product_posts = get_posts(
398 array(
399 'numberposts' => 1,
400 'orderby' => 'date',
401 'post_type' => Jetpack_Simple_Payments::$post_type_product,
402 'post_status' => 'publish',
403 )
404 );
405
406 return ! empty( $product_posts ) ? $product_posts[0]->ID : null;
407 }
408
409 /**
410 * Front-end display of widget.
411 *
412 * @see WP_Widget::widget()
413 *
414 * @param array $args Widget arguments.
415 * @param array $instance Saved values from database.
416 */
417 public function widget( $args, $instance ) {
418 $instance = wp_parse_args( $instance, $this->defaults() );
419
420 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
421
422 /** This filter is documented in core/src/wp-includes/default-widgets.php */
423 $title = apply_filters( 'widget_title', $instance['title'] );
424 if ( ! empty( $title ) ) {
425 echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
426 }
427
428 echo '<div class="jetpack-simple-payments-content">';
429
430 if ( ! empty( $instance['form_action'] ) && in_array( $instance['form_action'], array( 'add', 'edit' ), true ) && is_customize_preview() ) {
431 require __DIR__ . '/simple-payments/widget.php';
432 } else {
433 $jsp = Jetpack_Simple_Payments::get_instance();
434 $simple_payments_button = $jsp->parse_shortcode(
435 array(
436 'id' => $instance['product_post_id'],
437 )
438 );
439
440 if ( $simple_payments_button !== null || is_customize_preview() ) {
441 echo $simple_payments_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
442 }
443 }
444
445 echo '</div><!--simple-payments-->';
446
447 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
448
449 /** This action is already documented in modules/widgets/gravatar-profile.php */
450 do_action( 'jetpack_stats_extra', 'widget_view', 'simple_payments' );
451 }
452
453 /**
454 * Gets the latests field value from either the old instance or the new instance.
455 *
456 * @param array $new_instance mixed Array of values for the new form instance.
457 * @param array $old_instance mixed Array of values for the old form instance.
458 * @param mixed $field mixed Field value.
459 */
460 private function get_latest_field_value( $new_instance, $old_instance, $field ) {
461 return ! empty( $new_instance[ $field ] )
462 ? sanitize_text_field( $new_instance[ $field ] )
463 : $old_instance[ $field ];
464 }
465
466 /**
467 * Gets the product fields from the product post. If no post found
468 * it returns the default values.
469 *
470 * @param int $product_post_id Product Post ID.
471 * @return array $fields Product Fields from the Product Post.
472 */
473 private function get_product_from_post( $product_post_id ) {
474 $product_post = get_post( $product_post_id );
475 $form_product_id = $product_post_id;
476 if ( ! empty( $product_post ) ) {
477 $form_product_image_id = get_post_thumbnail_id( $product_post_id );
478
479 return array(
480 'form_product_id' => $form_product_id,
481 'form_product_title' => get_the_title( $product_post ),
482 'form_product_description' => $product_post->post_content,
483 'form_product_image_id' => $form_product_image_id,
484 'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
485 'form_product_currency' => get_post_meta( $product_post_id, 'spay_currency', true ),
486 'form_product_price' => get_post_meta( $product_post_id, 'spay_price', true ),
487 'form_product_multiple' => get_post_meta( $product_post_id, 'spay_multiple', true ) || '0',
488 'form_product_email' => get_post_meta( $product_post_id, 'spay_email', true ),
489 );
490 }
491
492 return $this->defaults();
493 }
494
495 /**
496 * Record a Track event and bump a MC stat.
497 *
498 * @param string $stat_name - the name of the stat.
499 * @param string $event_action - the action we're recording.
500 * @param array $event_properties - proprties of the event.
501 */
502 private function record_event( $stat_name, $event_action, $event_properties = array() ) {
503 $current_user = wp_get_current_user();
504
505 // `bumps_stats_extra` only exists on .com
506 if ( function_exists( 'bump_stats_extras' ) ) {
507 require_lib( 'tracks/client' );
508 tracks_record_event( $current_user, 'simple_payments_button_' . $event_action, $event_properties );
509 /** This action is documented in modules/widgets/social-media-icons.php */
510 do_action( 'jetpack_bump_stats_extra', 'jetpack-simple_payments', $stat_name );
511 return;
512 }
513
514 $tracking = new Tracking();
515 $tracking->tracks_record_event( $current_user, 'jetpack_wpa_simple_payments_button_' . $event_action, $event_properties );
516 $jetpack = Jetpack::init();
517 // $jetpack->stat automatically prepends the stat group with 'jetpack-'
518 $jetpack->stat( 'simple_payments', $stat_name );
519 $jetpack->do_stats( 'server_side' );
520 }
521
522 /**
523 * Sanitize widget form values as they are saved.
524 *
525 * @see WP_Widget::update()
526 *
527 * @param array $new_instance Values just sent to be saved.
528 * @param array $old_instance Previously saved values from database.
529 *
530 * @return array Updated safe values to be saved.
531 */
532 public function update( $new_instance, $old_instance ) {
533 $defaults = $this->defaults();
534 // do not overrite `product_post_id` for `$new_instance` with the defaults.
535 $new_instance = wp_parse_args( $new_instance, array_diff_key( $defaults, array( 'product_post_id' => 0 ) ) );
536 $old_instance = wp_parse_args( $old_instance, $defaults );
537
538 $required_widget_props = array(
539 'title' => $this->get_latest_field_value( $new_instance, $old_instance, 'title' ),
540 'product_post_id' => $this->get_latest_field_value( $new_instance, $old_instance, 'product_post_id' ),
541 'form_action' => $this->get_latest_field_value( $new_instance, $old_instance, 'form_action' ),
542 );
543
544 if ( strcmp( $new_instance['form_action'], $old_instance['form_action'] ) !== 0 ) {
545 if ( 'edit' === $new_instance['form_action'] ) {
546 return array_merge( $this->get_product_from_post( (int) $old_instance['product_post_id'] ), $required_widget_props );
547 }
548
549 if ( 'clear' === $new_instance['form_action'] ) {
550 return array_merge( $this->defaults(), $required_widget_props );
551 }
552 }
553
554 $form_product_image_id = (int) $new_instance['form_product_image_id'];
555
556 $form_product_email = ! empty( $new_instance['form_product_email'] )
557 ? sanitize_text_field( $new_instance['form_product_email'] )
558 : $defaults['form_product_email'];
559
560 return array_merge(
561 $required_widget_props,
562 array(
563 'form_product_id' => (int) $new_instance['form_product_id'],
564 'form_product_title' => sanitize_text_field( $new_instance['form_product_title'] ),
565 'form_product_description' => sanitize_text_field( $new_instance['form_product_description'] ),
566 'form_product_image_id' => $form_product_image_id,
567 'form_product_image_src' => wp_get_attachment_image_url( $form_product_image_id, 'thumbnail' ),
568 'form_product_currency' => sanitize_text_field( $new_instance['form_product_currency'] ),
569 'form_product_price' => sanitize_text_field( $new_instance['form_product_price'] ),
570 'form_product_multiple' => sanitize_text_field( $new_instance['form_product_multiple'] ),
571 'form_product_email' => $form_product_email,
572 )
573 );
574 }
575
576 /**
577 * Back-end widget form.
578 *
579 * @see WP_Widget::form()
580 *
581 * @param array $instance Previously saved values from database.
582 */
583 public function form( $instance ) {
584 $jetpack_simple_payments = Jetpack_Simple_Payments::get_instance();
585 if ( ! method_exists( $jetpack_simple_payments, 'is_enabled_jetpack_simple_payments' ) ) {
586 return;
587 }
588 if ( ! $jetpack_simple_payments->is_enabled_jetpack_simple_payments() ) {
589 require __DIR__ . '/simple-payments/admin-warning.php';
590 return;
591 }
592
593 $instance = wp_parse_args( $instance, $this->defaults() );
594
595 $product_posts = get_posts( // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
596 array(
597 'numberposts' => 100,
598 'orderby' => 'date',
599 'post_type' => Jetpack_Simple_Payments::$post_type_product,
600 'post_status' => 'publish',
601 )
602 );
603
604 require __DIR__ . '/simple-payments/form.php';
605 }
606 }
607
608 /**
609 * Register Jetpack_Simple_Payments_Widget widget.
610 */
611 function register_widget_jetpack_simple_payments() {
612 if ( ! class_exists( 'Jetpack_Simple_Payments' ) ) {
613 return;
614 }
615
616 $jetpack_simple_payments = Jetpack_Simple_Payments::get_instance();
617 if ( ! $jetpack_simple_payments->is_enabled_jetpack_simple_payments() ) {
618 return;
619 }
620
621 register_widget( 'Jetpack_Simple_Payments_Widget' );
622 }
623 add_action( 'widgets_init', 'register_widget_jetpack_simple_payments' );
624 }
625